SQL中的Delete语句非常慢

时间:2012-06-05 16:39:34

标签: sql sql-server sql-server-2008 database-optimization

我有这样的陈述超时:

DELETE FROM [table] WHERE [COL] IN ( '1', '2', '6', '12', '24', '7', '3', '5')

我试过这样做一次:

DELETE FROM [table] WHERE [COL] IN ( '1' )
到目前为止,到了22分钟仍在继续。

该表中有260,000行,并且是四列。

有没有人有任何想法为什么这会如此缓慢以及如何加快速度? 我确实在[COL]上有一个非唯一的非聚集索引,我在做WHERE。 我正在使用SQL Server 2008 R2

更新:我桌上没有触发器。

15 个答案:

答案 0 :(得分:70)

可能导致删除速度缓慢的事情:

  • 删除大量记录
  • 许多索引
  • 缺少子表中外键的索引。 (感谢@CesarAlvaradoDiaz在评论中提到这一点)
  • 死锁和阻止
  • 触发器
  • 级联删除(您删除的那10个父记录可能意味着 数以百万计的儿童记录被删除)
  • 需要增长的交易日志
  • 要检查的许多外键

因此,您的选择是找出阻塞并修复它的内容,或者在不关闭正常生产负载的情况下在非工作时间运行删除操作。您可以批量运行删除(如果您有触发器,级联删除或大量记录,则非常有用)。您可以删除并重新创建索引(如果您也可以在非工作时间执行此操作,则最好。)

答案 1 :(得分:46)

  1. 禁用CONSTRAINT

    ALTER TABLE [TableName] NOCHECK CONSTRAINT ALL;

  2. 禁用索引

    ALTER INDEX ALL ON [TableName] DISABLE;

  3. 重建索引

    ALTER INDEX ALL ON [TableName] REBUILD;

  4. 启用CONSTRAINT

    ALTER TABLE [TableName] CHECK CONSTRAINT ALL;

  5. 再次删除

答案 2 :(得分:17)

删除大量行可能会非常慢。尝试一次删除一些,例如:

delete top (10) YourTable where col in ('1','2','3','4')
while @@rowcount > 0
    begin
    delete top (10) YourTable where col in ('1','2','3','4')
    end

答案 3 :(得分:4)

预防措施

SQL Profiler的帮助下查看此问题的根本原因。可能Triggers导致执行延迟。它可以是任何东西。不要忘记在启动Database Name时选择Object NameTrace,以排除扫描不必要的查询...

<强> Database Name Filtering

<强> Table/Stored Procedure/Trigger Name Filtering

纠正措施

正如您所说,您的表包含260,000条记录...... IN Predicate包含六个值。现在,每个记录在IN Predicate中为每个值搜索260,000次。相反,它应该像下面的内部加入......

Delete K From YourTable1 K
Inner Join YourTable2 T on T.id = K.id

IN Predicate值插入Temporary TableLocal Variable

答案 4 :(得分:3)

如果你要删除的表有BEFORE / AFTER DELETE触发器,那么可能会导致你的延迟。

此外,如果您有引用该表的外键,则可能会发生其他更新或DELETE。

答案 5 :(得分:1)

其他表可能对您的[table]有FK约束。 因此,DB需要检查这些表以保持参照完整性。 即使您拥有与这些FK相对应的所有索引,也要检查它们的数量。

我遇到过NHibernate在同一列上错误地创建重复的FK 但具有不同名称(SQL Server允许)的情况。 它大大减慢了DELETE语句的运行速度。

答案 6 :(得分:0)

[COL]真的是一个持有数字的字符字段,还是可以摆脱值周围的单引号? @Alex是正确的,IN比=慢,所以如果你能做到这一点,你会更好:

DELETE FROM [table] WHERE [COL] = '1'

但更好的是使用数字而不是字符串来查找行(sql喜欢数字):

 DELETE FROM [table] WHERE [COL] = 1

也许试试:

 DELETE FROM [table] WHERE CAST([COL] AS INT) = 1

在任何一种情况下,请确保列[COL]上有索引以加快表扫描速度。

答案 7 :(得分:0)

检查此删除语句的执行计划。看看是否使用索引搜索。 col的数据类型是什么?

如果您使用的是错误的数据类型,请更改更新语句(例如从'1'更改为1或N'1')。

如果使用索引扫描,请考虑使用一些query hint ..

答案 8 :(得分:0)

我读过这篇文章,对于排除任何不便之处非常有帮助

https://support.microsoft.com/en-us/kb/224453

这是waitresource的一个案例 KEY:16:72057595075231744(ab74b4daaf17)

-- First SQL Provider to find the SPID (Session ID)

-- Second Identify problem, check Status, Open_tran, Lastwaittype, waittype, and waittime
-- iMPORTANT Waitresource select * from sys.sysprocesses where spid = 57

select * from sys.databases where database_id=16

-- with Waitresource check this to obtain object id 
select * from sys.partitions where hobt_id=72057595075231744

select * from sys.objects where object_id=2105058535

答案 9 :(得分:0)

如果你要删除表中的所有记录而不是少数几个记录,那么删除并重新创建表可能要快得多。

答案 10 :(得分:0)

就我而言,数据库统计信息已损坏。声明

delete from tablename where col1 = 'v1' 
即使没有匹配的记录,

也要花费30秒

delete from tablename where col1 = 'rubbish'

立即运行

运行

update statistics tablename

解决了问题

答案 11 :(得分:0)

在检查了SSIS程序包(由于SQL Server执行命令的速度非常慢)之后,该程序包是在我们撰写本文之前的5到4年间在我们客户中设置的,因此我发现以下内容任务: 1)将XML文件中的数据插入到名为[Importbarcdes]的表中。

2)使用上述表作为源,在另一个目标表上执行合并命令。

3)“从[导入条形码]中删除”,以清除SSIS包的任务读取XML文件后插入的行的表。

快速检查后,只有1行的表ImportBarcodes上的所有语句(SELECT,UPDATE,DELETE等)花费了大约2分钟的时间来执行。

扩展事件显示了很多PAGEIOLATCH_EX等待通知。

表中没有索引,也没有注册触发器。

在仔细检查表的属性后,在“存储”选项卡的“常规”部分下,“数据空间”字段显示了在页面中分配的超过6个GIGABYTES空间。

发生了什么:

在过去的4年中,查询每天都运行很大一部分时间,在表中插入和删除数据,将未使用的页面文件留在后面,而没有释放它们。

因此,这是扩展事件会话和表上执行缓慢的命令捕获的等待事件的主要原因。

运行ALTER TABLE ImportBarcodes REBUILD解决了释放所有未使用空间的问题。 TRUNCATE TABLE ImportBarcodes做了类似的事情,唯一的区别是删除了所有页面文件和数据。

答案 12 :(得分:0)

较旧的主题,但仍然有意义。 当索引变得零散到某种程度而不仅仅是帮助时,就会出现另一个问题。在这种情况下,答案是重建或删除并重新创建索引,然后再次发出delete语句。

答案 13 :(得分:0)

作为上述Andomar's answer的扩展,我有一个场景,其中前700,000,000条记录(约12亿条)的处理速度非常快,每秒(大致)25,000条记录的处理量。但是,开始需要15分钟才能完成25,000个批次。我将块大小减小到5,000条记录,并恢复到以前的速度。我不确定我达到了什么内部阈值,但是修复是为了减少记录数量,从而进一步提高速度。

答案 14 :(得分:-6)

打开CMD并运行此命令

NET STOP MSSQLSERVER
NET START MSSQLSERVER

这将重新启动SQL Server实例。 尝试在删除命令后再次运行

我在批处理脚本中有这个命令,如果遇到这样的问题,我会不时运行它。正常的PC重启将不会相同,因此如果您遇到sql服务器的某些问题,重启实例是最有效的方法。