【问题标题】:SQL For Update Skip Locked Query and Java Multi Threading - How to fix thisSQL For Update Skip Locked Query 和 Java 多线程 - 如何解决此问题
【发布时间】:2011-10-09 20:43:45
【问题描述】:
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 - 在从线程 1 更新 procs_dt 或提交之前,该线程执行该查询。我的要求是接下来的 10 个未锁定行必须移交给线程 2。但真正发生的是同一组锁定行来自内部查询,因为 procs_dt 仍然为空并且尚未由线程 1 更新,并且由于跳过在外部查询中给出了锁定,所有这 10 行都被跳过并且没有记录返回给线程 2 处理

这最终破坏了我的多线程要求。

如何修复此查询?我尝试将锁定的跳过添加到内部查询。但是 oracle 11g 不允许这样做。

请专家帮忙。我正在使用 oracle 11g

【问题讨论】:

  • 您已经告诉我们您在技术上做了哪些工作,哪些做不到。您能否还指定功能要求是什么?也许我们可以想出一个完全不同的方法。
  • 我有 2 个节点,其中运行相同批处理应用程序的 2 个实例。我有一个需要由这两个实例共享的数据库模式。 2个批处理实例需要同时查询一张表并处理那些记录一半/一半。如果表有 10k 条记录,我希望每个节点处理 5k 条记录。我正在使用 spring 批处理框架、oracle 11g 并进行面向块的处理。即节点将一次处理 10 条记录,然后获取 10 条记录的下一个块,然后继续处理,直到没有更多行要处理。我在处理记录时更新处理日期

标签: sql oracle concurrency locking oracle11g


【解决方案1】:

我会选择这样的东西: 用于选择行以进行更新的游标,并使用 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;

实际上,我首先会看看将所有未完成的行作为一个集合处理是否比多线程更好。

如果我确实决定需要某种形式的多线程,我会考虑启用并行的流水线函数(假设我使用的是企业版)。

【讨论】:

    【解决方案2】:

    只需从 where 条件中删除 result.rnum

    我不确定在手头有许多记录的情况下使用跳过锁定机制的性能如何。我已经针对此类问题实施了另一种解决方案;锁定具有特定类型的虚拟表以允许只有一个线程/应用程序能够查询具有特定类型的记录。

    如果可能,请告诉我跳过锁定的性能,谢谢。

    【讨论】:

      【解决方案3】:

      对于您的解决方案,您仍然可以订购您的记录,但如果您不必完全按照此订单更新记录,我的意思是它可以接近 98% 的订购或 smt,具体取决于您的记录有多大。您可以尝试以下解决方案随机选择您的记录

      解决方案:

      下面的查询很有用,但如果您的表很大,我只是尝试过,发现您肯定会遇到此查询的性能问题。

      SELECT * FROM ( SELECT * FROM table ORDER BY dbms_random.value ) WHERE rownum = 1
      

      因此,如果您设置如下所示的 rownum,则可以解决性能问题。通过增加 rownum 可以减少可能性。

      SELECT * FROM
          (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 <= 1000 ORDER BY dbms_random.value)
      WHERE rownum <= 10
      

      在选择行后更新行后,如果您无法更新,则表示另一个事务已使用它。然后您应该尝试获取新行并更新其状态。顺便说一句,由于 rownum 是 1000,所以两个不同的交易获得同一行的可能性是 0.001。

      【讨论】:

        猜你喜欢
        • 2021-12-05
        • 2016-01-29
        • 2019-04-16
        • 1970-01-01
        • 2011-04-25
        • 2016-08-14
        • 1970-01-01
        • 2018-08-18
        • 1970-01-01
        相关资源
        最近更新 更多