我应该在删除过程中锁定表吗

dsu*_*sum 3 sql-server

我有一张有 400 万条记录的表。它在日期列(记录创建日期)上有一个聚集索引。它有 5 个表引用这个表,都有 FK 索引。

机器没有停机时间。我有一个程序可以清理超过 31 天的记录。它创建一个连接,删除 TOP 1000 行,关闭连接,然后重复直到所有旧记录都被删除。

删除非常缓慢,每 10 秒删除大约 1000 行。理想情况下,我想每秒执行 1000 行。

我注意到在删除过程中,它对索引执行了大量页面锁定。

我想知道是否有更快的方法来删除数据而不会导致超时。

我的想法是,如果我做一个表锁,执行删除,等待一秒钟,以便它不会超时其他事务,然后再次执行删除,那会更好。我的猜测是,如果我做表锁,应该减少行锁或页锁的数量,这可能会加快删除速度。

我对这个问题的任何建议都会有所帮助。

请注意,硬盘或数据库没有碎片,它是 RAID 10 机器。

[更新] 感谢询问性能执行计划。看起来实时环境与我的开发环境不同。它正在执行索引扫描而不是索引查找。我想我必须更多地调查它为什么会进行索引扫描。 预计执行计划

[更新 2] 这是我们对其中一些表的索引。我们的索引命名约定是 [TableName]_[ColumnName],抱歉我们没有使用 MSSQL 命名标准。此外,事实证明,客户端有 96% 的碎片索引(VehicleLocationTP_VehicleLocationKey),这绝对是问题之一。这可能是 SQL2005 使用索引扫描而不是索引查找的原因在此处输入图片说明

[更新 3] 我终于能够在他们的测试服务器上测试删除查询,而不是在我自己的电脑上。他们在我的机器上运行 SQL 2005 Standard 和 SQL 2008 R2 Express。大约 95% 的索引碎片化,重建索引将删除从 25-50% 提高。当他们的 SQL Server 不断运行时,很难进行性能测试。但是,查看实际执行计划,它与估计的相同。所以你是对的,碎片不会影响执行计划。我的猜测是它可能是表中的行数。也许如果表很小,它会使用索引扫描,而不是索引查找。

此外,这篇文章让我更深入地了解为什么它是索引扫描Index Scan vs Index Seek

当执行计划显示索引扫描时,它真正扫描了整个表。它称之为索引扫描,因为 VehicleLocationAPC 是一个簇索引表。这消除了一些混乱。这意味着没有使用索引,它正在执行整个表扫描。

另一个需要意识到的是VehicleLocationAPC中数据的内容。VehicleLocationKey 几乎一直都是唯一的。我们的应用程序为每个 VehicileLocation 行生成一个 VehicleLocationAPC 行。我的猜测是,正因为如此,SQL Server 宁愿扫描整个表,而不是使用索引......但我可能是错的,因为我会认为索引在 b 树中排序,这应该是更快地扫描键,而不是进行表扫描。

我的重点转向 VehicleLocationTP,这是导致 63% 估计时间的表,而且这个表很大。

mrd*_*nny 5

将锁定更改为表锁定只会使删除运行得更慢,因为删除将无法运行,直到可以在表上获取锁定,这意味着所有其他线程都需要完成或阻塞。如果您的外键启用了删除级联,那可能会花费很多时间。

您可能希望将其更改为 SQL 代理作业,这样您就不必运行连接和断开连接的应用程序,而只需运行一个循环删除数据,直到完成。

SELECT NULL --Makes the WHILE loop work.
WHILE @@ROWCOUNT <> 0
BEGIN
    DELETE TOP (1000) FROM YourTable
    WHERE Column < getdate()-31
END
Run Code Online (Sandbox Code Playgroud)

如果这不起作用,您可以查看表分区,这将允许您非常快速地将数据切换到另一个表,然后从新表中截断数据。但是,这确实需要企业版。