gpt4 book ai didi

java - Oracle 表就像一个队列

转载 作者:搜寻专家 更新时间:2023-11-01 03:35:19 24 4
gpt4 key购买 nike

我们有一个非常高并发的应用程序,其中一些要处理的键与它们的处理优先级一起不断地写入到 Oracle 11g 表中。该表上有一个来自序列的主键(ID 字段)。 KEY 字段有 UNIQUE 约束。

ID    KEY        PRIORITY
-------------------------
1 ABC 0
2 XYZ 5
3 AZW 0
...
100 CNS 7

上面的表格以非常高的速度被插入,比如说每分钟大约一万条记录。我们还有大约 100 个并行消费者,他们不断汇集上表寻找工作。一个这样的消费者一次只需要一个 key 来处理,但重要的是,不能有两个具有相同 key 的消费者同时发送给多个消费者。处理应该发生在PRIORITY 后跟 ID 顺序。

为了满足这一点,消费者最终调用了如下函数:

FUNCTION select_key RETURN VARCHAR2
IS
v_key VARCHAR2(64) := NULL;

CURSOR keys IS
SELECT key
FROM my_table
ORDER BY priority, id
FOR UPDATE SKIP LOCKED;
BEGIN
OPEN keys
LOOP
FETCH keys INTO v_key;
EXIT WHEN keys%NOTFOUND;
DELETE FROM my_table WHERE key = v_key;
EXIT WHEN SQL%ROWCOUNT > 0;
END LOOP;
CLOSE keys;

RETURN v_key;
END;

因为这个表被插入和删除的频率如此之高,所以那个表上的统计数据很快就变得陈旧了。上面SELECT的执行计划是全表扫描。这导致 key 选择过程花费的时间越来越长,并且随着时间的推移性能显着下降。

除此之外,因为 ORACLE 锁定在数据 block 级别而不是记录级别,我们遇到的处理并不是真正发生在 PRIORITY 后跟 ID 顺序中。这对我们来说并不是什么大问题,但仍然是我们希望避免的事情。

这种方法的另一个更大的问题是,您每次都针对一个表运行完整的 SQL,该表可以轻松地获取几万条记录,只是为了获取一个键。

我想到的第一个想法是为此使用一个真正的队列,并从中为我的并发消费者提供服务。然而,我最终在同步我的表和队列提要时遇到了各种问题,最终我放弃了这个想法。

任何关于我应该如何更好地解决这个问题的建议都将不胜感激。

提前谢谢你。

最佳答案

在 (PRIORITY, ID) 上创建索引,然后查询可以使用 INDEX FULL SCAN 按顺序读取数据,而不是扫描整个表。

示例表和数据

drop table my_table;

create table my_table
(
key varchar2(100) not null,
id number not null,
priority number not null,
constraint my_table_pk primary key (key)
);

insert into my_table
select level, level, level
from dual connect by level <= 100000;

begin
dbms_stats.gather_table_stats(user, 'MY_TABLE');
end;
/

带全表扫描的正常解释计划

explain plan for
select key
from my_table
order by priority, id;

select * from table(dbms_xplan.display);


Plan hash value: 3656711297

---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 1562K| | 637 (1)| 00:00:01 |
| 1 | SORT ORDER BY | | 100K| 1562K| 2760K| 637 (1)| 00:00:01 |
| 2 | TABLE ACCESS FULL| MY_TABLE | 100K| 1562K| | 103 (1)| 00:00:01 |
---------------------------------------------------------------------------------------

为更好的索引访问计划创建索引

成本一开始看起来并不好。但真正的版本应该快得多,因为它会很快停止处理。

create index my_table_idx on my_table(priority, id);

explain plan for
select key
from my_table
order by priority, id;

select * from table(dbms_xplan.display);

Plan hash value: 2209255802

--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 1562K| 577 (1)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| MY_TABLE | 100K| 1562K| 577 (1)| 00:00:01 |
| 2 | INDEX FULL SCAN | MY_TABLE_IDX | 100K| | 292 (1)| 00:00:01 |
--------------------------------------------------------------------------------------------

关于java - Oracle 表就像一个队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33816750/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com