【发布时间】:2017-03-01 18:25:34
【问题描述】:
我有一个存储过程,它使用以下语句将记录插入到我们的 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 有唯一性约束。在某些情况下,我的插入语句失败,因为表中已经存在主键。当它发生时,我希望我的存储过程循环并重试插入,直到它成功。
我使用以下方法尝试了多种解决方案,但均未成功:
-
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;
【问题讨论】:
-
只有在并行运行 SP 时,密钥才能存在。您应该简单地切换到 WRITE 锁,而不是处理并发问题:
LOCK TABLE UAT_AUDIT_VIEWS.AUDIT_BATCH FOR WRITE INSERT ... -
我确实有多个团队并行调用存储过程。我们实现了一个 WRITE LOCK 作为第一个解决方案,但是当存在并发访问时它最终导致了死锁问题。这就是为什么我想删除它,捕获插入错误并重试。如果您有其他选择,我会感兴趣吗?
-
当与表级别的 WRITE 锁并行运行时,您发布的插入不会导致死锁。另一种解决方案(扩展性更好)基于一个序列表,该表的单行存储最大值,您的 SP 读取当前值,将其加一并将其写回。
-
感谢您的评论。我仍然认为 WRITE 锁是死锁问题的原因,因为我们能够重现该问题并将其删除,我们注意到该问题不再发生(但我们有 BATCH_KEY 唯一性约束错误)。我不明白为什么将 Max(BATCH_KEY) 存储在专用表中可以解决这两个问题中的任何一个?
标签: loops error-handling insert teradata