1

我有一个在 ORacle 10g 生产数据库中运行的作业,它同步两个数据库表 A 和 B。该作业从表 A 中获取数据并插入到表 B 中。该作业每天运行,在过去的几个月中,它开始在生产中失败出现错误“检索数据时出错 -54”。在检查存储过程时,当其他作业锁定表 A 中的记录并且我们的作业无法处理相同的记录时,我可以看到作业由于锁定记录问题而失败。所以我开始寻找我在下面给出的一些可能的解决方案。

  1. 更改作业的运行时间,以便它可以处理记录。但这无济于事,因为表 A 非常关键,并且总是被生产作业使用。它还具有来自用户的实时更新。

  2. 使用“SKIP LOCKED”代替“No WAIT”,这样作业将跳过锁定的记录并正常运行。但是这里的问题是,如果跳过锁定的记录(这与庞大的生产数据相比总是可以忽略不计),那么当天表A和B中的数据就会不匹配。第二天运行将清除此问题,因为作业也会选择前几天未选择的记录。但是作业失败天数的轻微不匹配可能会导致小问题

  3. 让作业等到所有记录都被解锁和处理。但这又会导致问题,因为我们无法预测作业将处于等待状态(长时间运行状态)多长时间。

到目前为止,对我来说一种可能的解决方案是使用选项 2,并忽略表 A 和 Bs 数据之间的微小偏差。Oracle 10g Db 中是否有任何其他方式可以运行作业而不会失败并长时间运行并处理所有记录。我希望得到一些技术指导。

谢谢铅

4

1 回答 1

2

我会处理异常(注意,您必须自己初始化EXCEPTION或处理OTHERS并检查SQLCODE)并跟踪被跳过的行的 ID。这样,您可以在处理完所有可用记录后重试它们。

像这样的东西:

DECLARE

  row_is_locked EXCEPTION;
  PRAGMA EXCEPTION_INIT(row_is_locked, -54);

  TYPE t_id_type IS VARRAY(1) OF INTEGER;
  l_locked_ids t_id_type := t_id_type();

  l_row test_table_a%ROWTYPE;

BEGIN

  FOR i IN (
    SELECT a.id
    FROM test_table_a a
  )
  LOOP

    BEGIN

      -- Simulating your processing that requires locks
      SELECT *
      INTO l_row
      FROM test_table_a a
      WHERE a.id = i.id
      FOR UPDATE NOWAIT;

      INSERT INTO test_table_b 
      VALUES l_row;

      -- This is on the basis that you're commiting
      -- to release the lock on each row after you've
      -- processed it; may not be necessary in your case
      COMMIT;

    EXCEPTION

      WHEN row_is_locked THEN
        l_locked_ids(l_locked_ids.LAST) := i.id;
        l_locked_ids.EXTEND();

    END;

  END LOOP;

  IF l_locked_ids.COUNT > 0 THEN
    FOR i IN l_locked_ids.FIRST .. l_locked_ids.LAST LOOP
      -- Reconcile the remaining ids here
      NULL;
    END LOOP;
  END IF;

END;
于 2012-11-21T08:26:11.210 回答