SELECT
id
FROM table_name tkn1,
(SELECT
id,
ROWNUM rnum
FROM table_name
WHERE
PROCS_DT is null
order by PRTY desc, CRET_DT) result
WHERE tkn1.id= result.id
AND result.rnum <= 10 FOR UPDATE OF tkn1.id SKIP LOCKED
这是我的问题。 2个线程同时访问此查询
线程1 - 执行选择并锁定按降序优先级和创建日期排序的10行。接下来,我将从单独的查询中将procs_dt更新为今天的日期..
线程2 - 在更新procs_dt或从线程1发生提交之前,此线程执行此查询。我的要求是接下来的10个未锁定的行必须移交给线程2.但是真正发生的是同一组锁定的行来自内部查询,因为procs_dt仍为null并且尚未被线程1更新并且因为跳过在外部查询中给出了锁定,跳过了所有这10行,并且没有为线程2返回任何记录来处理
这最终会破坏我的多线程要求。
如何修复此查询?我尝试添加锁定到内部查询的跳过。但是oracle 11g不允许它。
专家请帮忙。我正在使用oracle 11g
答案 0 :(得分:5)
我会选择这样的东西: 用于选择行以进行更新的游标,并使用LIMIT子句获得前十个可用的行。
create table gm_temp
as select rownum id, table_name obj_name, date '2011-01-01' + rownum create_date
from all_tables where rownum < 500;
CREATE TYPE tab_number IS TABLE OF NUMBER;
DECLARE
cursor c_table IS
SELECT id FROM gm_temp ORDER BY create_date DESC FOR UPDATE OF id SKIP LOCKED;
t_table_src tab_number := tab_number();
BEGIN
OPEN c_table;
FETCH c_table BULK COLLECT INTO t_table_src LIMIT 10;
CLOSE c_table;
dbms_output.put_line(':'||t_table_src.count||':'||t_table_src(1));
END;
实际上,我首先要看看将所有未完成的行作为一组进行处理会比多线程更好。
然后,如果我确定我需要某种形式的多线程,我会看一下并行启用的流水线函数(假设我在企业版上)。
答案 1 :(得分:1)
从你的where条件中删除result.rnum&lt; = 10。 跳过锁定机制实际上以不同的方式工作。 即使从查询中删除rownum,它也不会锁定所有行,而是“获取”行。 因此,不要使用rownum = 10,只需将fetchSize设置为10.它将满足您的需求。
我不确定的是如何使用具有许多记录的跳过锁定机制的性能。我已经为这种问题实施了另一种解决方案;锁定具有特定类型的虚拟表,以便只允许一个线程/应用程序查询具有特定类型的记录。
如果可能的话,让我知道跳过锁定的性能,thx。
答案 2 :(得分:0)
对于您的解决方案,您仍然可以订购您的记录,但如果您不必使用此订单更新记录,我的意思是根据您的记录大小,它可以接近98%的订购或smt。您可以尝试以下解决方案随机选择您的记录
解决方案:
下面的查询很有用但是如果你的表很大,我只是尝试看到你肯定会遇到这个查询的性能问题。
SELECT * FROM(SELECT * FROM table ORDER BY dbms_random.value)WHERE rownum = 1
因此,如果您设置如下所示的rownum,那么您可以解决性能问题。通过递增rownum,您可以减少可能性。
SELECT * FROM (选择 ID FROM table_name tkn1, (选择 ID, ROWNUM rnum FROM table_name 哪里 PROCS_DT为空 按PRTY desc命令,CRET_DT)结果 在哪里tkn1.id = result.id AND result.rnum&lt; = 1000 ORDER BY dbms_random.value) rownum&lt; = 10
在选择行后更新行,如果无法更新,则意味着另一个事务已经使用过它。然后您应该尝试获取新行并更新其状态。顺便说一下,由于rownum是1000,因此通过两种不同的交易可能性获得相同的行是0.001。