为什么我的SQL Server删除查询计划中存在问题排序?

时间:2014-01-29 20:36:48

标签: sql-server

我在SQL Server 2012(网络版)中有一个非常大的表(150米+行),它没有聚簇索引和一个非聚集索引。

当我运行此删除语句时:

DELETE TOP(500000) 
FROM pick 
WHERE tournament_id < 157

(列名在非聚集索引中),SQL Server生成的执行计划如下所示:

query plan

排序步骤看起来有问题 - 它占用了45%的成本,并且它正在引发一条警告说“操作员在执行期间使用tempdb溢出数据”。该查询需要几分钟才能运行,我觉得它应该更快。

两个问题:

  1. 为什么计划中有一个分步?
  2. 任何想法如何克服漏油事件?服务器有64GB的RAM,tempdb的大小为8x 4gb数据文件。
  3. 如果可能有帮助,我绝对可以重新访问此表上的索引策略。

    希望这一切都有意义 - 提前感谢任何提示。

3 个答案:

答案 0 :(得分:6)

我同意这里似乎没有充分的理由。

我不认为万圣节保护需要它,因为它没有出现在计划的= 157版本中。

此外,排序操作按Key Asc, Bmk ASC的顺序排序(可能是按照索引顺序按顺序排序),但这是正向索引在同一索引上搜索的顺序,无论如何都要返回行。 / p>

删除它的一种方法是混淆TOP以获得狭窄(每行)而不是宽(每个索引)计划。

DECLARE @N INT = 500000

DELETE TOP(@N) 
FROM pick
WHERE  tournament_id < 157 
OPTION (OPTIMIZE FOR (@N=1))

enter image description here

您需要进行测试,看看这是否真的有所改善。

答案 1 :(得分:3)

我会尝试更小的块和更具选择性的WHERE子句,以及强制SQL Server按照您指定的顺序选择TOP行的方法:

;WITH x AS
(
  SELECT TOP (10000) tournament_id
  FROM dbo.pick
  WHERE tournament_id < 157 -- AND some other where clause perhaps?
  ORDER BY tournament_id -- , AND some other ordering column
)
DELETE x;

更具选择性也可能意味着删除tournament_id&lt; 20,然后是tournament_id&lt; 40等,而不是从1-157中挑选500000个随机行。通常情况下,对整个系统(阻止影响,锁定升级等以及对日志的影响)执行一系列小事务而不是一个大事务更好。我在这里写了博客:http://www.sqlperformance.com/2013/03/io-subsystem/chunk-deletes

在这些情况下可能仍然存在这种情况(特别是如果它适用于Hallowe'en保护或与RID有关),但在较小的范围内它可能远没有问题(请不要只是基于在那个估计的成本%数,因为这些数字通常是垃圾)。所以首先我要考虑添加聚簇索引。没有更多的要求我没有给你一个明确的建议,但它可以像仅在tournament_id上的聚集索引一样简单(取决于你每个id有多少潜在的行)或添加你可能使用的IDENTITY列帮助确定将来要删除的行。

答案 2 :(得分:2)

我是以下步骤:

  1. 在列tournament_id
  2. 上创建一个集群索引
  3. 更新数据库的统计信息
  4. 再次运行您的查询
  5. 根据我的经验,这应该会有几秒钟。

    此外,如果可能,我会对您的表格进行更详细的查询。

    版本1(日期格式为dd / mm / yyyy):

    ;WITH To_Delete
    (
    SELECT tournament_id
    FROM dbo.pick
    WHERE tournmanet_id < 157
    AND date like '01/%/2013' -- if available, Need to be customized
    AND date like '03/%/2013' -- if available, Need to be customized
    )
    DELETE X;
    

    Verion 2(具有month功能,无论您的日期具有哪种格式):

    ;WITH To_Delete
    (
    SELECT tournament_id
    FROM dbo.pick
    WHERE tournmanet_id < 157
    AND month(date) = 1
    AND month(date) < 3
    )
    DELETE X;