【发布时间】:2019-06-12 15:37:23
【问题描述】:
我们使用的是 SQL Server 2017。我们有 READ_COMMITTED_SNAPSHOT ON。我们有一个执行删除然后插入的查询,如下所示:
begin transaction
SELECT DISTINCT STAGING.MyTable.CategoryId
INTO #categories_to_delete
FROM STAGING.MyTable;
commit;
begin transaction;
SELECT DISTINCT STAGING.MyTable.ItemId
INTO #items_to_delete
FROM STAGING.MyTable;
commit;
begin transaction;
DELETE FROM PROD.MyTableProd
FROM PROD.MyTableProd
INNER JOIN #categories_to_delete
ON #categories_to_delete.CategoryId = PROD.MyTableProd.CategoryId;
commit;
begin transaction;
DELETE FROM PROD.MyTableProd
FROM PROD.MyTableProd
INNER JOIN #items_to_delete
ON #items_to_delete.ItemId= PROD.MyTableProd.ItemId;
commit;
begin transaction;
INSERT INTO PROD.MyTableProd
SELECT
CategoryId
, ItemId
, <other_columns>
FROM
STAGING.MyTable;
commit;
PROD.MyTableProd 和STAGING.MyTable 的主键都是ItemId。 prod 表有大约 1200 万行,而 staging 表在上一步中插入数据时会被截断。
运行时,我们会经常在insert 上遇到主键违规。我的怀疑是因为READ_COMMITTED_SNAPSHOT ON,insert 和delete 锁没有相互阻塞,所以insert 发生在delete 还没有完成时?但是,我认为将所有内容包装在事务中可以防止出现此类问题?有什么建议可以防止这些主键问题而无需关闭READ_COMMITTED_SNAPSHOT?有没有办法只为这张桌子关闭它?
【问题讨论】:
-
您使用 DISTINCT 生成要删除的项目列表这一事实表明您的表具有重复的 ItemID 值。也许只是很少。要验证这一点,请在脚本开头检查临时表中的重复 ItemId 值并引发错误。
-
它不考虑两个表具有相同的主键列。
标签: sql sql-server database tsql