sql server delete被索引大幅减速

时间:2010-01-15 19:36:34

标签: sql-server stored-procedures optimization sql-delete

我正在运行一个归档脚本,该脚本根据输入的日期从大型(~50m记录DB)中删除行。日期字段是表上的聚簇索引,因此我将条件语句应用于。

我在while循环中运行此删除,尝试批量处理1000到100,000条记录。无论批量大小,它都非常缓慢;像10,000条记录一样被删除一分钟。查看执行计划,“索引删除”花费了大量时间。表中大约有15个字段,其中大约有10个字段具有某种索引。有什么方法可以解决这个问题吗?我甚至不确定为什么每次删除索引都需要这么长时间,有人可以对这里发生的具体事件有所了解吗?这是我执行计划的一个示例:

alt text http://img94.imageshack.us/img94/1006/indexdelete.png

(序列指向删除命令)

这个数据库是实时的,并且经常被插入,这就是为什么我对使用修剪大小的复制和截断方法犹豫不决。我在这里还有其他选择吗?

5 个答案:

答案 0 :(得分:6)

从聚集索引+ 5个非聚类索引中删除10k记录应该定义为1分钟。听起来你有一个非常慢的IO子系统。有什么价值:

  • 平均。磁盘秒/写
  • 平均。磁盘秒/读
  • 平均。磁盘写入队列长度
  • 平均。磁盘读取队列长度

在操作中涉及的每个驱动器上(包括Log对象!)。如果将索引放在单独的文件组中并将每个文件组分配给自己的LUN或自己的磁盘,则可以确定哪些索引更有问题。此外,日志刷新可能是一个主要瓶颈。 SQL Server在这里没有太多控制权,一切都在你手中如何加快速度。该时间不用于CPU周期,等待IO完成,您需要为您需要的负载校准IO子系统。

要减少IO负载,您应该考虑使索引更窄。首先,确保聚集索引是最有效的。然后,确保非聚簇索引不包括繁琐的未使用的大列(我已经看到了......)。启用page compression可能会获得重大收益。最后,检查sys.dm_db_index_usage_stats中的索引使用情况统计数据,看看是否有任何索引对斧头有利。

如果无法大幅降低IO负载,则应尝试拆分它。将文件组添加到数据库,在单独的文件组上移动大索引,将文件组放在单独的IO路径(不同的轴)上。

对于将来的常规删除操作,最好的选择是使用分区切换,让所有索引与聚簇索引分区对齐,当时间到期时,只需删除最后一个分区即可快速删除。

答案 1 :(得分:3)

假设表中的每条记录都有5条索引记录。

现在每次删除本质上都是5次操作。

除此之外,您还有一个聚集索引。注意聚簇索引删除时间很长? (10x)比其他指数更长?这是因为您删除的每条记录都会重新组织您的数据。

我建议至少删除该索引,进行批量删除,而不是重新应用。删除和插入的索引操作本身就很昂贵。单次重建可能要快得多。

答案 2 :(得分:2)

我认为@NickLarsen在评论中提出的建议。找出你是否有unused indexes并删除它们。这可以减少那些索引删除的开销,这可能足以使操作更加及时。

另一个更激进的策略是删除所有索引,执行删除,然后快速重新创建现在较小数据集的索引。这不一定会中断服务,但在此期间可能会使查询速度变慢。虽然我不是Microsoft SQL Server专家,所以你应该对这个策略提出一些建议。

答案 3 :(得分:1)

更多解决方法,但是您可以向表中添加IsDeleted标志并将其更新为1而不是删除行吗?您需要修改SELECTsUPDATEs才能使用此标记。

然后,您可以安排在非工作时间删除或存档这些记录。

答案 4 :(得分:1)

实现它需要一些工作,因为这是在生产中,但如果你在SQL Server 2005/2008上,你应该调查并将表转换为分区,然后可以非常快速地实现旧数据的删除。它设计用于“滚动窗口”类型的效果,并防止大规模删除绑定表/进程。

不幸的是,随着生产中的表的使用,将其迁移到这种技术将需要一些T-SQL编码,知识和周末来升级/迁移它。一旦到位,虽然任何现有的选择和插入都将无缝地对其起作用,但是分区维护和添加/删除是您需要t-sql来控制该过程的地方。