调查 PL/SQL 中的 ORA-00001

Investigating ORA-00001 in PL/SQL

我们上次在生产中执行存储过程时 运行 进入了 ORA-00001。 存储过程直到昨天都运行良好,我尝试排除故障但没有任何进展。

如果您能在下面提供一些有用的想法,我们将不胜感激..

我将情况细分为: 1) Table 带主键, 2)一个序列 3) 一个存储过程。

1) 我们主要 table 如下:

CREATE TABLE MY_MESSAGES (MESSAGE_ID NUMBER, MESSAGE VARCHAR2(200));
CREATE UNIQUE INDEX MY_MESSAGES_PK ON MY_MESSAGES (MESSAGE_ID);
ALTER TABLE MY_MESSAGES ADD CONSTRAINT MY_MESSAGES_PK PRIMARY KEY (MESSAGE_ID) USING INDEX  ENABLE;

2) 一个序列

CREATE SEQUENCE  MESSAGE_ID_SEQUENCE;

独立备份table:

CREATE TABLE MY_MESSAGES_BKP (BKP_ID VARCHAR2(200), RECIVED_TIME TIMESTAMP, MESSAGE VARCHAR2(200));
INSERT INTO MY_MESSAGES_BKP VALUES('201', TIMESTAMP '2018-09-26 00:00:00.000000', 'MSG206');
INSERT INTO MY_MESSAGES_BKP VALUES('202', TIMESTAMP '2018-09-26 05:00:00.000000', 'MSG206');
INSERT INTO MY_MESSAGES_BKP VALUES('203', TIMESTAMP '2018-09-26 06:00:00.000000', 'MSG207');
INSERT INTO MY_MESSAGES_BKP VALUES('204', TIMESTAMP '2018-09-26 07:00:00.000000', 'MSG208');
INSERT INTO MY_MESSAGES_BKP VALUES('205', TIMESTAMP '2018-09-26 08:00:00.000000', 'MSG209');
COMMIT;

3) 最后,存储过程:

DECLARE
  TYPE VARCHAR_TABLE IS TABLE OF VARCHAR(200);
  V_MESSAGE_ID NUMBER(20) := 0;
  V_BKP_IDS VARCHAR_TABLE := VARCHAR_TABLE();
  V_EXC_QUERY VARCHAR2(200) := 'INSERT INTO MY_MESSAGES(MESSAGE_ID, MESSAGE) SELECT :1, MESSAGE FROM  MY_MESSAGES_BKP WHERE BKP_ID = :2';
BEGIN
  SELECT BKP_ID BULK COLLECT INTO V_BKP_IDS FROM MY_MESSAGES_BKP WHERE RECIVED_TIME > TIMESTAMP '2018-09-26 00:00:00.000000';

  FOR I IN 1..V_BKP_IDS.COUNT LOOP
    EXECUTE IMMEDIATE 'SELECT MESSAGE_ID_SEQUENCE.NEXTVAL FROM DUAL' INTO V_MESSAGE_ID ;
    EXECUTE IMMEDIATE V_EXC_QUERY USING V_MESSAGE_ID, V_BKP_IDS(I);
  END LOOP;
  V_BKP_IDS.DELETE;
EXCEPTION
    WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE(SQLERRM); 
END;
/

知道,table MY_MESSAGES 被使用相同序列 (MESSAGE_ID_SEQUENCE) 作为主键的其他进程使用..

存储过程 运行ning 了一段时间,它从 ~5000 条记录中插入了 400 多条记录.. 然后它停止并出现以下错误:

ORA-00001: unique constraint my_messages_pk) violated

此外,在调查 table 之后,我们发现成功插入的记录的所有主键在停止之前都是顺序的..

另一个进程在后台 运行ning 完全正常,我们可以看到插入的记录也是顺序的,但是存储过程插入的最后一条记录和下一条插入的记录之间有 1 个数字差距另一个进程。

也就是说MESSAGE_ID_SEQUENCE.NEXTVAL被存储过程执行了,但是没有插入记录。

如果存储过程停止,tables 没有带主键的记录。

可能出了什么问题? 我们如何进一步调查?

最直接的解释是,在 ORA-00001 的情况下,此 select SELECT :1, MESSAGE FROM MY_MESSAGES_BKP WHERE BKP_ID = :2 发现不止一行 BKP_ID = :2。这反过来会导致插入 INSERT INTO MY_MESSAGES(MESSAGE_ID, MESSAGE) SELECT :1, MESSAGE FROM MY_MESSAGES_BKP WHERE BKP_ID = :2 多次使用序列中的相同数字。 HTH