5

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

我在一个while循环中运行这个删除,批量尝试从1000到100,000条记录。无论批量大小,它都非常慢;每分钟删除 10,000 条记录。查看执行计划,在“索引删除”上花费了很多时间。表中大约有 15 个字段,其中大约 10 个字段上有某种索引。有没有办法解决这个问题?我什至不确定为什么每次删除索引都需要这么长时间,有人可以解释一下这里到底发生了什么吗?这是我的执行计划示例:

替代文字 http://img94.imageshack.us/img94/1006/indexdelete.png

(序列指向删除命令)

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

4

5 回答 5

6

Deleting 10k records from a clustered index + 5 non clustered ones should definetely not take 1 minute. Sounds like you have a really really slow IO subsytem. What are the values for:

  • Avg. Disk sec/Write
  • Avg. Disk sec/Read
  • Avg. Disk Write Queue Length
  • Avg. Disk Read Queue Length

On each drive involved in the operation (including the Log ones!). If you placed indexes in separate filegroups and allocated each filegroup to its own LUN or own disk, then you can identify which indexes are more problematic. Also, the log flush may be a major bottleneck. SQL Server doesn't have much control here, is all in your own hands how to speed things up. that time is not spent in CPU cycles, is spent waiting for IO to complete and you need an IO subsystem calibrated for the load you demand.

To reduce the IO load you should look into making indexes narrower. Primarily, make sure the clustered index is the narrowest possible that works. Then, make sure the nonclustered indexes don't include sporious unused large columns (I've seen that...). A major gain may be had by enabling page compression. And ultimately, inspect index usage stats in sys.dm_db_index_usage_stats and see if any index is good for the axe.

If you can't reduce the IO load much, you should try to split it. Add filegroups to the database, move large indexes on separate filegroups, place the filegroups on separate IO paths (distinct spindles).

For future regular delete operations, the best alternative is to use partition switching, have all indexes aligned with the clustered index partitioning and when the time is due, just drop the last partition for a lightning fast deletion.

于 2010-01-15T20:32:22.653 回答
3

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

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

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

我建议至少删除该索引,进行批量删除,而不是重新申请。删除和插入的索引操作本质上是昂贵的。一次重建可能要快得多。

于 2010-01-15T20:16:58.773 回答
2

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

另一个更激进的策略是删除所有索引,执行删除,然后为现在更小的数据集快速重新创建索引。这不一定会中断服务,但同时它可能会使查询速度变慢。虽然我不是 Microsoft SQL Server 专家,但您应该对我的建议持保留态度。

于 2010-01-15T20:04:31.200 回答
1

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

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

于 2010-01-15T19:39:25.883 回答
1

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

不幸的是,对于生产中的表,将其迁移到这种技术将需要一些 T-SQL 编码、知识和一个周末来升级/迁移它。一旦到位,尽管任何现有的选择和插入都可以无缝地对其进行操作,但分区维护和添加/删除是您需要 t-sql 控制过程的地方。

于 2010-01-15T19:51:55.340 回答