【发布时间】:2016-02-22 08:30:33
【问题描述】:
我们有一个非常高并发的应用程序,其中一些要处理的键与它们的处理优先级一起不断地写入 Oracle 11g 表中。该表上有一个来自序列的主键(ID 字段)。 KEY 字段有一个 UNIQUE 约束。
ID KEY PRIORITY
-------------------------
1 ABC 0
2 XYZ 5
3 AZW 0
...
100 CNS 7
上面的表格以非常高的速度插入,比如每分钟大约一万条记录。我们还有大约 100 个并行消费者,它们不断地汇集上表寻找工作。一个这样的消费者一次只需要一个密钥来处理,但至关重要的是,不能两个有相同的密钥一次发送给多个消费者。处理应该发生在PRIORITY,然后是@ 987654323@下单。
为了满足这一点,消费者最终会调用如下函数:
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 的执行计划显示了全表扫描。这会导致密钥选择过程花费的时间越来越长,并且性能会随着时间的推移而显着下降。
除此之外,因为 ORACLE 锁定在数据块级别而不是记录级别,我们遇到的处理并未真正发生在 PRIORITY 后跟 ID 的顺序中。这对我们来说并不是什么大问题,但仍然是我们希望避免的。
这种方法的另一个更大的问题是,您每次都针对一个表运行完整的 SQL,而该表可以轻松获取几万条记录,只是为了获取一个键。
我想到的第一个想法是为此使用一个真正的队列,并让我的并发消费者从中服务。然而,我最终在同步我的表格和队列提要时遇到了各种各样的问题,最终我放弃了这个想法。
任何关于我应该如何更好地解决这个问题的建议将不胜感激。
提前谢谢你。
【问题讨论】:
-
使用 oracle 减少地图 :)
-
能否用 Java 重写队列,让消费者转而询问 Java 代码?
-
@Peeyush:通读那个 atm @Thorbjørn Ravn Andersen:将队列保留在内存中不是一种选择。不仅因为我们的应用程序是在多个 JVM 中运行的分布式应用程序,而且很难实现跨国行为
-
所以您的问题本质上是如何让 Oracle 正常运行?有一个网站!
-
使用 Oracle AQ 有什么问题?
标签: java oracle performance mq