我有一个存储过程将记录插入Teradata数据仓库中的表中,并带有以下语句:
INSERT INTO UAT_AUDIT_VIEWS.AUDIT_BATCH(
BATCH_KEY
,AUDIT_STATUS_KEY
,BATCH_START_DATETIME
,BATCH_END_DATETIME
,BATCH_OWNER
,BATCH_EXECUTION_START_DATETIME
,BATCH_EXECUTION_END_DATETIME
)
VALUES(
(SELECT COALESCE(MAX(BATCH_KEY),0)+1 FROM UAT_AUDIT_VIEWS.AUDIT_BATCH)
,5 --PENDING
,'1900-01-01 00:00:00'
,'2999-12-31 00:00:00'
,:P_BATCH_OWNER
,CURRENT_TIMESTAMP
,'2999-12-31 00:00:00'
);
请注意,我对主键BATCH_KEY有一个unicity约束。在某些情况下,我的insert语句失败,因为主键已存在于表中。当它发生时,我希望我的存储过程循环并重试插入,直到它成功。
我使用以下方法尝试了多种解决方案,但未成功:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
以避免插入失败时存储过程失败WHILE DO
循环您能描述一下如何管理这种情况吗? 这是我为测试它而构建的测试存储过程的简化版本(它不起作用):
REPLACE PROCEDURE DEV_AUDIT_NEW.ARO_TEST_INSERT()
BEGIN
DECLARE V_BATCH_KEY_CREATED VARCHAR(100);
DECLARE V_COUNTER SMALLINT DEFAULT 1;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
SET V_BATCH_KEY_CREATED = NULL;
WHILE V_BATCH_KEY_CREATED IS NULL
DO
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST_LOG(LOG_DESC) VALUES(V_BATCH_KEY_CREATED);
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST(BATCH_KEY,BATCH_OWNER) VALUES(V_COUNTER,'B');
SELECT BATCH_KEY
INTO :V_BATCH_KEY_CREATED
FROM DEV_AUDIT_NEW.AUDIT_BATCH_TEST
WHERE BATCH_KEY=V_COUNTER AND BATCH_OWNER='B';
SET V_COUNTER=V_COUNTER+1;
INSERT INTO DEV_AUDIT_NEW.AUDIT_BATCH_TEST_LOG(LOG_DESC) VALUES(V_BATCH_KEY_CREATED);
END WHILE;
END;
答案 0 :(得分:1)
这个评论太长了。
您当前的方法必须执行全表扫描以获取MAX(默认为表级别的读锁定),但Insert默认为在行哈希级别上写锁定。当您在表级请求Write时,它应该防止死锁。
当您定义一种序列表时,每次访问都是UPI访问,例如
CREATE SET TABLE Sequences
(
SequenceName VARCHAR(128) CHARACTER SET Unicode NOT CaseSpecific NOT NULL,
nextVal BIGINT NOT NULL DEFAULT 1
)
UNIQUE PRIMARY INDEX ( SequenceName )
;
REPLACE PROCEDURE NextVal (IN SequenceName VARCHAR(128) CHARACTER SET Unicode, OUT NextVal BIGINT)
BEGIN
BEGIN REQUEST
LOCK ROW WRITE
SELECT nextVal INTO :nextVal FROM Sequences
WHERE SequenceName = :SequenceName;
UPDATE Sequences SET nextVal = nextVal + 1
WHERE SequenceName = :SequenceName;
END REQUEST;
END;
初始化一个新序列:
INSERT INTO sequences ('mytable', 1);
获取下一个值:
CALL nextVal('mytable', nextval);`
编辑:
您可以使用并行多个会话的BTEQ记录轻松测试它,例如在10个会话中运行1000个CALL:
.set session 10;
.logon ...;
select * from sequences where SequenceName = 'mytable';
.repeat 1000
CALL nextVal('mytable', nextval);
select * from sequences where SequenceName = 'mytable';
观察按顺序返回的值,没有死锁: - )