在删除并插入到READ_COMMITTED_SNAPSHOT ON的SQL Server时出现问题

时间:2019-06-12 15:37:23

标签: sql sql-server database tsql

我们正在使用SQL Server2017。我们有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.MyTableProdSTAGING.MyTable上的主键均为ItemId。 prod表大约有1200万行,而在上一步中插入数据时,staging表将被截断。

运行此命令时,我们经常会在insert上遇到违反主键的情况。我的怀疑是,由于READ_COMMITTED_SNAPSHOT ONinsertdelete锁没有互相阻塞,所以insert发生在delete没有吃完了吗但是,我认为将所有内容包装在交易中将防止出现此类问题?对于防止关闭这些主键问题而不必关闭READ_COMMITTED_SNAPSHOT有什么建议?有没有办法仅在这张桌子上放它?

2 个答案:

答案 0 :(得分:0)

这是一个数据库设置,您不能按表进行设置,但是...

如果仅将RCSI设置为ON,它只会将已提交的读操作更改为快照读。更新,插入和删除使用正常的事务隔离进行处理。

  

设置READ_COMMITTED_SNAPSHOT ON选项可以访问   默认的READ COMMITTED隔离级别下版本化的行。

Snapshot Isolation in SQL Server

在任何情况下,由于快照隔离,您都不会看到PK违规,尽管如果在同一行上有两个并发的更新/插入/删除,则可以看到更新冲突。

答案 1 :(得分:0)

  

运行此命令时,我们经常会在插入内容上遇到违反主键的情况。我的怀疑   是因为READ_COMMITTED_SNAPSHOT ON,插入和删除锁没有彼此阻塞,所以插入是在删除未完成时发生的吗?

对于每个命令,您要使用不同的事务,如果您希望在插入后将它们放入同一事务后进行删除,例如

开始交易 选择DISTINCT STAGING.MyTable.CategoryId INTO #categories_to_delete 来自STAGING.MyTable;

从PROD.MyTableProd中删除 从PROD.MyTableProd 内联#categories_to_delete 开启#categories_to_delete.CategoryId = PROD.MyTableProd.CategoryId; 提交;

开始交易; 选择DISTINCT STAGING.MyTable.ItemId INTO #items_to_delete 来自STAGING.MyTable;

从PROD.MyTableProd中删除 从PROD.MyTableProd 内联#items_to_delete 开启#items_to_delete.ItemId = PROD.MyTableProd.ItemId; 提交;

启用READ_COMMITTED_SNAPSHOT时,事务不会互相阻塞,因为所有事务在初始事务开始时都会读取表的快照。