Sql server 删除表中的行会导致锁定
我正在运行以下命令从一个大表(1.5亿行)中批量删除行:Sql server 删除表中的行会导致锁定,sql-server,sql-server-2008,tsql,Sql Server,Sql Server 2008,Tsql,我正在运行以下命令从一个大表(1.5亿行)中批量删除行: DECLARE@RowCount int 而1=1 开始 删除顶部(10000)t1 来自表t1 t2上的内部联接表2 t2.PrimaryKey=t1.PrimaryKey 我想你的思路是对的 再看看这两篇文章: 以及: 在运行删除之前,请检查估计的查询计划,看看它是否正确 正在为删除执行索引查找,还是仍在执行完整表 扫描/访问 首先-看起来您的DELETE正在执行聚集索引扫描,我建议您执行以下操作: create index
DECLARE@RowCount int
而1=1
开始
删除顶部(10000)t1
来自表t1
t2上的内部联接表2 t2.PrimaryKey=t1.PrimaryKey
我想你的思路是对的
再看看这两篇文章:
以及:
在运行删除之前,请检查估计的查询计划,看看它是否正确
正在为删除执行索引查找,还是仍在执行完整表
扫描/访问
首先-看起来您的DELETE正在执行聚集索引扫描,我建议您执行以下操作:
create index [IX.IndexName] ON t1(YearProcessed, PrimaryKey)
第二,是否需要加入t2表
然后使用以下查询删除行,假设PrimaryKey列的类型为INT:
declare @ids TABLE(PrimaryKey INT)
WHILE 1=1
BEGIN
INSERT @ids
SELECT top 10000 DISTINCT t1.PrimaryKey
FROM table t1
INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey
WHERE t1.YearProcessed <= 2007
IF @@ROWCOUNT = 0 BREAK
DELETE t1
WHERE PrimaryKey in (Select PrimaryKey from @ids)
delete from @ids
END
declare@ids表(PrimaryKey INT)
而1=1
开始
插入@ids
选择top 10000 DISTINCT t1.PrimaryKey
来自表t1
t2上的内部联接表2 t2.PrimaryKey=t1.PrimaryKey
其中t1.YearProcessed除了其他建议(旨在减少删除过程中所做的工作)之外,还可以将SQL Server配置为在表上执行删除操作时不阻止其他读卡器
这可以通过使用SQL Server 2005引入的“快照隔离”来实现:
我过去也见过类似的零星问题,即使在5000条记录的小批量中,锁定仍然会发生。在我们的例子中,每个删除/更新都包含在自己的Begin Tran…Commit循环中。要纠正这个问题,需要
等待延迟“00:00:00:01”
已放置在每个循环的顶部,从而更正了问题。如果您有任何级联删除,请确保它们已被索引
突出显示删除查询并单击“显示估计的执行计划”
将显示建议的索引,在我的例子中,这些索引包括一些级联删除
为这些行添加索引使删除速度大大加快,但我仍然不会尝试一次删除所有行。我找到的最佳方法是表单asp.net DeleteExpiredSessions。执行READUNCOMMITED select并将记录放入临时表中,然后使用光标删除记录
ALTER PROCEDURE [dbo].[DeleteExpiredSessions]
AS
SET NOCOUNT ON
SET DEADLOCK_PRIORITY LOW
DECLARE @now datetime
SET @now = GETUTCDATE()
CREATE TABLE #tblExpiredSessions
(
SessionID nvarchar(88) NOT NULL PRIMARY KEY
)
INSERT #tblExpiredSessions (SessionID)
SELECT SessionID
FROM [ASPState].dbo.ASPStateTempSessions WITH (READUNCOMMITTED)
WHERE Expires < @now
IF @@ROWCOUNT <> 0
BEGIN
DECLARE ExpiredSessionCursor CURSOR LOCAL FORWARD_ONLY READ_ONLY
FOR SELECT SessionID FROM #tblExpiredSessions
DECLARE @SessionID nvarchar(88)
OPEN ExpiredSessionCursor
FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID
WHILE @@FETCH_STATUS = 0
BEGIN
DELETE FROM [ASPState].dbo.ASPStateTempSessions WHERE SessionID = @SessionID AND Expires < @now
FETCH NEXT FROM ExpiredSessionCursor INTO @SessionID
END
CLOSE ExpiredSessionCursor
DEALLOCATE ExpiredSessionCursor
END
DROP TABLE #tblExpiredSessions
RETURN 0
ALTER过程[dbo]。[DeleteExpiredSessions]
作为
不计较
将死锁设置为低优先级
声明@now datetime
SET@now=GETUTCDATE()
创建表#tblExpiredSessions
(
SessionID nvarchar(88)主键不为空
)
插入#tblExpiredSessions(SessionID)
选择SessionID
来自[ASPState].dbo.ASPStateTempSessions与(READUNCOMMITTED)
现在在哪里
如果@@ROWCOUNT 0
开始
声明ExpiredSessionCursor游标本地转发只读
对于从#tblExpiredSessions中选择SessionID
声明@SessionID nvarchar(88)
打开过期的sessioncursor
从ExpiredSessionCursor获取下一个到@SessionID
而@@FETCH\u STATUS=0
开始
从[ASPState].dbo.ASPStateTempSessions中删除,其中SessionID=@SessionID并立即过期
从ExpiredSessionCursor获取下一个到@SessionID
结束
关闭过期的sessioncursor
取消分配过期的SessionCursor
结束
DROP TABLE#tblExpiredSessions
返回0
试试这个
DECLARE @RowCount int
WHILE 1=1
BEGIN
BEGIN TRANSACTION
DELETE TOP (10000) t1
FROM table t1
INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey
WHERE t1.YearProcessed <= 2007
END TRANSACTION
COMMIT TRANSACTION
SET @RowCount = @@ROWCOUNT
IF (@RowCount < 10000) BREAK
END
DECLARE@RowCount int
而1=1
开始
开始交易
删除顶部(10000)t1
来自表t1
t2上的内部联接表2 t2.PrimaryKey=t1.PrimaryKey
其中t1.YearProcessed实际上是从父表内部连接要删除的主键列表(实际上在表变量中)。我刚刚发布了两个表来简化脚本编写。与您所做的非常相似,但您采用了不同的方法,我将尝试这种方法。值得注意的是,快照隔离需要更改单个事务的隔离级别。读取提交的快照隔离将更改默认隔离级别,但它需要一个非常短暂的中断。这是在每个批处理或每行删除的开始/结束时进行的?
DECLARE @RowCount int
WHILE 1=1
BEGIN
BEGIN TRANSACTION
DELETE TOP (10000) t1
FROM table t1
INNER JOIN table2 t2 ON t2.PrimaryKey = t1.PrimaryKey
WHERE t1.YearProcessed <= 2007
END TRANSACTION
COMMIT TRANSACTION
SET @RowCount = @@ROWCOUNT
IF (@RowCount < 10000) BREAK
END