多重循环锁定 SQL 服务器数据库
Multiple Loop gives lock in SQL Server database
我很难理解我在 SQL Server 2008 中看到的行为。
我必须创建一个作业,以不创建任何锁的方式删除表中的一些数据。我被建议使用循环来解决这个问题,因为这些表被大量使用并且非常大。
所以下面的 运行 非常完美,而且当我 运行 自行设置时,查询不会锁定数据库:
DECLARE @pkQ BIGINT
DECLARE DEL_CURSOR CURSOR STATIC FOR Select PK from Table1 where Inserted_Date <= DateAdd(WEEK, -1, Getdate()) order by PK desc
OPEN DEL_CURSOR
FETCH NEXT FROM DEL_CURSOR into @pkQ
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE TOP(10) from Table1 where PK <= @pkQ
FETCH NEXT FROM DEL_CURSOR into @pkQ
PRINT '10 deleted from Table1'
WaitFor DELAY '00:00:01'
END
CLOSE DEL_CURSOR
DEALLOCATE DEL_CURSOR
PRINT 'Cursor Closed'
但是,如果我有 2 个不同的光标,它就会中断。
DECLARE @pkQ BIGINT
DECLARE DEL_CURSOR CURSOR STATIC FOR Select PK from Table1 where Inserted_Date <= DateAdd(WEEK, -1, Getdate()) order by PK desc
OPEN DEL_CURSOR
FETCH NEXT FROM DEL_CURSOR into @pkQ
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE TOP(10) from Table1 where PK <= @pkQ
FETCH NEXT FROM DEL_CURSOR into @pkQ
PRINT '10 deleted from Table1'
WaitFor DELAY '00:00:01'
END
CLOSE DEL_CURSOR
DEALLOCATE DEL_CURSOR
PRINT ''Cursor Closed''
print N'In SecondCursor'
DECLARE DEL_CURSORR CURSOR FOR Select top 1000 PK from Table2 where Insert_Date < DateAdd(Month, -6, Getdate()) order by PK desc
OPEN DEL_CURSORR
FETCH NEXT FROM DEL_CURSORR into @pkQ
WHILE @@FETCH_STATUS = 0
BEGIN
WAITFOR DELAY '00:00:02'
Delete top(10) from Table2 where PK <= @pkQ
FETCH NEXT FROM DEL_CURSORR into @pkQ
WaitFor DELAY '00:00:01'
PRINT '10 deleted from Table2'
END
CLOSE DEL_CURSORR
DEALLOCATE DEL_CURSORR
当我同时拥有 运行 并尝试查询表 1 或表 2 中的任何内容时,它只是被锁定了。
这是我为此设置的测试数据:
DROP TABLE IF EXISTS #Table1;
DROP TABLE IF EXISTS #Table2;
SELECT 1001999 + n AS ID
INTO #Table1
FROM (SELECT TOP (30000)
n = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]) AS x;
SELECT 1001999 + n AS ID
INTO #Table2
FROM (SELECT TOP (30000)
n = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]) AS x;
使用的数据集(可能)比您要删除的数据集小得多。
当我 运行 您指定的 DELETE
模式时,每个光标中都有 WAITFOR DELAY
,我让它 运行 20 分钟,然后才给出之上。消息窗格中未打印任何内容,它的行为与您描述的一样。
当我注释掉等待时,代码(修改以适合我的示例)如下所示:
DECLARE @pkQ BIGINT;
DECLARE DEL_CURSOR CURSOR STATIC FOR
SELECT ID
FROM #Table1
ORDER BY ID DESC;
OPEN DEL_CURSOR;
FETCH NEXT FROM DEL_CURSOR
INTO @pkQ;
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE TOP (10)
FROM #Table1
WHERE ID <= @pkQ;
FETCH NEXT FROM DEL_CURSOR
INTO @pkQ;
PRINT '10 deleted from Table1';
--WAITFOR DELAY '00:00:01';
END;
CLOSE DEL_CURSOR;
DEALLOCATE DEL_CURSOR;
PRINT 'Cursor Closed';
PRINT N'In SecondCursor';
DECLARE DEL_CURSORR CURSOR FOR
SELECT TOP 1000
ID
FROM #Table2
ORDER BY ID DESC;
OPEN DEL_CURSORR;
FETCH NEXT FROM DEL_CURSORR
INTO @pkQ;
WHILE @@FETCH_STATUS = 0
BEGIN
--WAITFOR DELAY '00:00:02';
DELETE TOP (10)
FROM #Table2
WHERE ID <= @pkQ;
FETCH NEXT FROM DEL_CURSORR
INTO @pkQ;
--WAITFOR DELAY '00:00:01';
PRINT '10 deleted from Table2';
END;
CLOSE DEL_CURSORR;
DEALLOCATE DEL_CURSORR;
我在 6 秒内成功完成。
即使只有区区 30k 行,WAITFOR DELAY 00:00:01
也会为此任务增加 50 分钟的非生产时间。
最后说明:根据表的大小和要删除的数量,您可能会在 Brent Ozar 的 post 博客中找到关于“快速有序删除”的博客 - 它不会让你绕过删除集,但它可能会帮助你在不影响并发的情况下做到这一点
https://www.brentozar.com/archive/2018/04/how-to-delete-just-some-rows-from-a-really-big-table/
我很难理解我在 SQL Server 2008 中看到的行为。
我必须创建一个作业,以不创建任何锁的方式删除表中的一些数据。我被建议使用循环来解决这个问题,因为这些表被大量使用并且非常大。
所以下面的 运行 非常完美,而且当我 运行 自行设置时,查询不会锁定数据库:
DECLARE @pkQ BIGINT
DECLARE DEL_CURSOR CURSOR STATIC FOR Select PK from Table1 where Inserted_Date <= DateAdd(WEEK, -1, Getdate()) order by PK desc
OPEN DEL_CURSOR
FETCH NEXT FROM DEL_CURSOR into @pkQ
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE TOP(10) from Table1 where PK <= @pkQ
FETCH NEXT FROM DEL_CURSOR into @pkQ
PRINT '10 deleted from Table1'
WaitFor DELAY '00:00:01'
END
CLOSE DEL_CURSOR
DEALLOCATE DEL_CURSOR
PRINT 'Cursor Closed'
但是,如果我有 2 个不同的光标,它就会中断。
DECLARE @pkQ BIGINT
DECLARE DEL_CURSOR CURSOR STATIC FOR Select PK from Table1 where Inserted_Date <= DateAdd(WEEK, -1, Getdate()) order by PK desc
OPEN DEL_CURSOR
FETCH NEXT FROM DEL_CURSOR into @pkQ
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE TOP(10) from Table1 where PK <= @pkQ
FETCH NEXT FROM DEL_CURSOR into @pkQ
PRINT '10 deleted from Table1'
WaitFor DELAY '00:00:01'
END
CLOSE DEL_CURSOR
DEALLOCATE DEL_CURSOR
PRINT ''Cursor Closed''
print N'In SecondCursor'
DECLARE DEL_CURSORR CURSOR FOR Select top 1000 PK from Table2 where Insert_Date < DateAdd(Month, -6, Getdate()) order by PK desc
OPEN DEL_CURSORR
FETCH NEXT FROM DEL_CURSORR into @pkQ
WHILE @@FETCH_STATUS = 0
BEGIN
WAITFOR DELAY '00:00:02'
Delete top(10) from Table2 where PK <= @pkQ
FETCH NEXT FROM DEL_CURSORR into @pkQ
WaitFor DELAY '00:00:01'
PRINT '10 deleted from Table2'
END
CLOSE DEL_CURSORR
DEALLOCATE DEL_CURSORR
当我同时拥有 运行 并尝试查询表 1 或表 2 中的任何内容时,它只是被锁定了。
这是我为此设置的测试数据:
DROP TABLE IF EXISTS #Table1;
DROP TABLE IF EXISTS #Table2;
SELECT 1001999 + n AS ID
INTO #Table1
FROM (SELECT TOP (30000)
n = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]) AS x;
SELECT 1001999 + n AS ID
INTO #Table2
FROM (SELECT TOP (30000)
n = ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1
CROSS JOIN sys.all_objects AS s2
ORDER BY s1.[object_id]) AS x;
使用的数据集(可能)比您要删除的数据集小得多。
当我 运行 您指定的 DELETE
模式时,每个光标中都有 WAITFOR DELAY
,我让它 运行 20 分钟,然后才给出之上。消息窗格中未打印任何内容,它的行为与您描述的一样。
当我注释掉等待时,代码(修改以适合我的示例)如下所示:
DECLARE @pkQ BIGINT;
DECLARE DEL_CURSOR CURSOR STATIC FOR
SELECT ID
FROM #Table1
ORDER BY ID DESC;
OPEN DEL_CURSOR;
FETCH NEXT FROM DEL_CURSOR
INTO @pkQ;
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE TOP (10)
FROM #Table1
WHERE ID <= @pkQ;
FETCH NEXT FROM DEL_CURSOR
INTO @pkQ;
PRINT '10 deleted from Table1';
--WAITFOR DELAY '00:00:01';
END;
CLOSE DEL_CURSOR;
DEALLOCATE DEL_CURSOR;
PRINT 'Cursor Closed';
PRINT N'In SecondCursor';
DECLARE DEL_CURSORR CURSOR FOR
SELECT TOP 1000
ID
FROM #Table2
ORDER BY ID DESC;
OPEN DEL_CURSORR;
FETCH NEXT FROM DEL_CURSORR
INTO @pkQ;
WHILE @@FETCH_STATUS = 0
BEGIN
--WAITFOR DELAY '00:00:02';
DELETE TOP (10)
FROM #Table2
WHERE ID <= @pkQ;
FETCH NEXT FROM DEL_CURSORR
INTO @pkQ;
--WAITFOR DELAY '00:00:01';
PRINT '10 deleted from Table2';
END;
CLOSE DEL_CURSORR;
DEALLOCATE DEL_CURSORR;
我在 6 秒内成功完成。
即使只有区区 30k 行,WAITFOR DELAY 00:00:01
也会为此任务增加 50 分钟的非生产时间。
最后说明:根据表的大小和要删除的数量,您可能会在 Brent Ozar 的 post 博客中找到关于“快速有序删除”的博客 - 它不会让你绕过删除集,但它可能会帮助你在不影响并发的情况下做到这一点 https://www.brentozar.com/archive/2018/04/how-to-delete-just-some-rows-from-a-really-big-table/