Delete
有时很慢,我经常需要优化它们以减少所需的时间。
我一直在寻找有关如何做到这一点的提示,我发现了各种各样的建议。
我想知道你最喜欢和最有效的技术,以驯服删除野兽,以及它们的工作方式和原因。
直到现在:
确保外键具有索引
确保索引的条件
使用WITH ROWLOCK
销毁未使用的索引,删除,重建索引
现在轮到你了。
答案 0 :(得分:22)
您可能会对以下文章快速订购删除操作感兴趣。
Performing fast SQL Server delete operations
该解决方案侧重于利用视图来简化为批量删除操作生成的执行计划。这是通过引用给定的表一次而不是两次来实现的,这反过来又减少了所需的I / O量。
答案 1 :(得分:13)
我对Oracle有更多的经验,但很可能同样适用于SQL Server:
答案 2 :(得分:9)
我想知道是不是垃圾收集数据库的时候了?您将行标记为删除,服务器稍后在扫描期间将其删除。你不希望每次删除都有这个 - 因为有时一行必须现在去 - 但它偶尔会很方便。
答案 3 :(得分:7)
2014-11-05答案摘要
这个答案被标记为社区维基,因为这是一个不断发展的主题,有很多细微差别,但整体答案很少。
第一个问题是你必须问问自己你正在优化的场景是什么?这通常是在db上具有单个用户的性能,或者在db上具有许多用户的扩展。有时答案恰恰相反。
对于单用户优化
TABLELOCK
SET ROWCOUNT 20000
(或其他任何东西,取决于日志空间)和循环(可能带有WAITFOR DELAY
),直到你全部删除它(@@ROWCOUNT = 0
)适用于多用户优化
进行一般优化
WHERE
子句具有索引WHERE
子句中删除的行,而不是直接引用该表。 [Read more...] 答案 4 :(得分:5)
说实话,从表中删除一百万行的方式与插入或更新一百万行一样严重。问题是行集的大小,你可以做的并不多。
我的建议:
答案 5 :(得分:4)
(如果索引是“未使用”,为什么它们一直存在?)
我过去使用的一个选项是批量完成工作。粗略的方法是使用SET ROWCOUNT 20000
(或其他)和循环(可能带有WAITFOR DELAY
)直到你完全摆脱它(@@ ROWCOUNT = 0)。
这可能有助于减少对其他系统的影响。
答案 6 :(得分:4)
问题是你还没有充分定义你的条件。即究竟是什么优化的?
例如,系统是否已进行夜间维护,系统中没有用户?你在删除大部分数据库吗?
如果离线并删除大的%,可能只需构建一个包含要保留的数据的新表,删除旧表并重命名。如果删除小%,您可能希望按日志空间允许的大批量批量处理。它完全取决于您的数据库,但在重建期间丢弃索引可能会有所帮助 - 如果可能的话,由于“离线”而可能会有所帮助。
如果您在线,您的删除与用户活动发生冲突的可能性是什么(用户活动主要是读取,更新还是什么)?或者,您是否尝试优化用户体验或完成查询的速度?如果要从其他用户经常更新的表中删除,则需要批量但批量较小的表。即使您执行类似表锁的操作来强制隔离,如果您的删除语句需要一个小时,那也没有多大用处。
当您更好地定义条件时,可以在此处选择其中一个答案。我喜欢Rob Sanders关于批量处理的帖子中的链接。
答案 7 :(得分:3)
如果您有许多外键表,请从链的底部开始并进行操作。如果没有级联删除的子记录,那么最终的删除会更快并阻止更少的事情(如果我有大量的子表,我将不会打开,因为它会杀死性能)。
批量删除。
如果你有不再使用的外键表(你会惊讶地发现生产数据库最终会因旧表而没有人会摆脱),摆脱它们或者至少打破FK / PK连接。如果没有使用记录,就没有任何意义来为记录查询。
不要删除 - 将记录标记为已删除,然后从所有查询中排除已标记的记录。这是在数据库设计时最好设置的。很多人都使用这个,因为它也是获取记录意外删除的最快最快的方法。但是在现有系统中进行设置需要做很多工作。
答案 8 :(得分:2)
我将在此添加另一个:
确保正确设置事务隔离级别和数据库选项。如果您的SQL服务器设置为不使用行版本控制,或者您正在等待删除行的其他查询上使用隔离级别,那么您可能会在操作发生时为自己设置一些非常差的性能
答案 9 :(得分:2)
在非常大的表上,您有一组非常具体的删除条件,您还可以对表进行分区,切换分区,然后处理删除。
SQLCAT团队一直在真正真正大量数据上使用这种技术。我找到了一些引用here,但我会尝试找到更明确的东西。
答案 10 :(得分:2)
我认为,删除杀死性能的大陷阱是每行删除后的sql,它会更新此行中任何列的所有相关索引。如何在批量删除之前删除所有索引?
答案 11 :(得分:1)
有删除然后删除。如果要将数据作为修剪作业的一部分老化,则希望能够通过聚簇键删除连续的行块。如果你必须使来自不连续的高容量表的数据老化,那将是非常痛苦的。
答案 12 :(得分:1)
如果UPDATES比DELETES更快,您可以在选择中添加一个名为DELETED的状态列并对其进行过滤。然后在晚上运行一个执行实际删除的过程。
答案 13 :(得分:1)
您是否启用了引用完整性的外键? 你有触发器有效吗?
答案 14 :(得分:0)
简化WHERE子句中函数的任何使用!例如:
DELETE FROM Claims
WHERE dbo.YearMonthGet(DataFileYearMonth) = dbo.YearMonthGet(@DataFileYearMonth)
这种形式的WHERE
条款需要8分钟才能删除125,837条记录。
YearMonthGet
函数用输入日期的年份和月份组成日期,并设置day = 1
。这是为了确保我们根据年月而不是月中删除记录。
我将WHERE子句重写为:
WHERE YEAR(DataFileYearMonth) = YEAR(@DataFileYearMonth)
AND MONTH(DataFileYearMonth) = MONTH(@DataFileYearMonth)
结果:删除大约需要38-44秒才能删除这些125,837条记录!