Sql server sql server删除速度因索引而急剧降低
我正在运行一个归档脚本,它根据输入日期从一个大的(~50m记录数据库)中删除行。日期字段是表上的聚集索引,因此也是我应用条件语句的目的 我在while循环中运行这个delete,一批尝试1000到100000条记录。不管批量大小,它的速度惊人地慢;大约每分钟有10000条记录被删除。看看执行计划,有很多时间花在“索引删除”上。表中大约有15个字段,其中大约10个字段上有某种索引。有没有办法绕过这个问题?我甚至不知道为什么每次删除索引都要花这么长时间,有人能解释一下这里到底发生了什么吗?这是我的执行计划示例: (序列指向Delete命令)Sql server sql server删除速度因索引而急剧降低,sql-server,stored-procedures,optimization,sql-delete,Sql Server,Stored Procedures,Optimization,Sql Delete,我正在运行一个归档脚本,它根据输入日期从一个大的(~50m记录数据库)中删除行。日期字段是表上的聚集索引,因此也是我应用条件语句的目的 我在while循环中运行这个delete,一批尝试1000到100000条记录。不管批量大小,它的速度惊人地慢;大约每分钟有10000条记录被删除。看看执行计划,有很多时间花在“索引删除”上。表中大约有15个字段,其中大约10个字段上有某种索引。有没有办法绕过这个问题?我甚至不知道为什么每次删除索引都要花这么长时间,有人能解释一下这里到底发生了什么吗?这是我的执
这个数据库是实时的,并且经常被插入到数据库中,这就是为什么我不愿意使用复制和截断方法来调整大小。这里是否缺少其他选项?更多的解决方法,但是您是否可以向表中添加
IsDeleted
标志,并将其更新为1
,而不是删除行?您需要修改选择
和更新
以使用此标志
然后,您可以安排在下班时间删除或归档这些记录。考虑到这是在生产中,实施这些记录需要一些工作,但是如果您使用的是SQL Server 2005/2008,您应该调查并将表转换为分区表,那么可以非常快地删除旧数据。它是为“滚动窗口”类型的效果而设计的,可以防止大规模的删除占用表/进程
不幸的是,由于该表已投入生产,将其迁移到这种技术将需要一些T-SQL编码、知识和一个周末来升级/迁移它。一旦到位,尽管任何现有的选择和插入都会无缝地与之对抗,但分区维护和添加/删除是您需要t-sql来控制进程的地方。我支持@NickLarsen在评论中提出的建议。看看你有没有,把它们扔了。这可以减少这些索引删除的开销,这可能足以使操作更加及时
另一个更激进的策略是删除所有索引,执行删除,然后为现在更小的数据集快速重新创建索引。这并不一定会中断服务,但同时可能会使查询速度慢得多。虽然我不是Microsoft SQL Server专家,但您应该对我的建议持保留态度。假设表中的每条记录都有5条索引记录 现在每个删除本质上是5个操作 此外,还有一个聚集索引。请注意,聚集索引删除时间非常长?(10倍)比其他指数长?这是因为您的数据正在重新组织,每个记录都已删除
我建议至少删除那个索引,进行大规模删除,而不是重新应用。对delete和insert进行索引操作的成本很高。一次重建可能要快得多。从聚集索引中删除10k条记录+5条非聚集记录肯定不会花费1分钟。听起来你的IO子系统非常慢。以下各项的价值是什么:
- 平均磁盘秒/写入
- 平均磁盘秒/读取
- 平均磁盘写入队列长度
- 平均磁盘读取队列长度
对于将来的常规删除操作,最好的替代方法是使用分区切换,使所有索引与聚集索引分区对齐,到期时,只需删除最后一个分区即可进行闪电般的删除。是否完全需要所有这些索引?如果你不使用索引,你应该去掉它们。我刚刚和我们网站上的主要程序员谈过,听起来我们可能不再需要所有的索引了。当我们对表进行一些查询时,它更常用作日志类型表。在再次运行删除脚本之前,我可能会尝试删除一些插入。好吧,我打算每天在非工作时间定期运行此脚本以保持数据库修剪(它会删除任何超过2年的记录),但初始运行速度太慢,目前需要大约4个小时才能完成,这比那些想把服务器绑起来的权力还多。谢谢你的建议!在这种情况下,只需一次删除较小的批(例如,1000个),以便从最终用户的角度看不会对服务器负载产生明显的影响,并在每个循环之间以30-60秒的延迟重复此操作。然后让它运行直到完成。可能需要一周或更长时间