查看聚集索引超过50万行需要7分钟

时间:2013-09-03 16:59:15

标签: sql sql-server performance indexed-view indexed-views

看看这个执行计划:http://sdrv.ms/1agLg7K
这不是估计的,而是实际的。从实际执行大约 30分钟

选择第二个陈述(占总执行时间的47.8% - 大约15分钟) 查看该语句中的top操作 - 查看Clustered Index Seek over _Security_Tuple4。 运营成本占声明的51.2% - 大约7分钟。

该视图包含大约0.5M行(作为参考,log2(0.5M)〜= 19 - 如果索引树节点大小为2,则仅仅19步,实际上可能更高)。
该运算符的结果是零行(与估计值不匹配,但现在不记得了。) 实际执行 - 零。

所以问题是:哔哔声怎么可能需要7分钟?! (当然,我该如何解决?)


编辑对我在这里要求的内容进行了一些澄清
对一般性能相关的建议感兴趣,例如“查看索引”,“查看大小”,“参数嗅探”,“不同数据的不同执行计划”等。 /> 我已经知道了所有这些,我可以自己做那种分析。

我真正需要的是知道什么可能导致某个特定聚集索引寻求如此缓慢,然后我该怎么做才能加快

整个查询。
查询的任何部分。
只是一个特定的指数寻求 结束编辑


另请注意第二和第三最昂贵的操作如何分别在_Security_Tuple3和_Security_Tuple2上进行搜索,它们只占7.5%和3.7%的时间。同时,_Security_Tuple3包含大约2.8M行,是_Security_Tuple4的六倍。

还有一些背景知识:

  1. 这是该项目唯一行为不端的数据库。 有几十个相同模式的其他数据库,没有一个表现出这个问题。
  2. 第一次发现此问题时,结果发现索引碎片占99%。 重建索引确实加快了速度,但并不显着:整个查询在重建之前需要45分钟,之后需要30分钟。
  3. 在玩数据库时,我注意到像“从_Security_Tuple4中选择计数(*)”之类的简单查询需要几分钟时间。 WTF?!
  4. 然而,他们在第一轮比赛中只花了几分钟,之后他们就立刻了。
  5. 问题是连接到特定服务器,也没有连接到特定的SQL Server实例:如果我备份数据库然后在另一台计算机上恢复它,行为将保持不变。

3 个答案:

答案 0 :(得分:3)

首先,我想在这里指出一点误解:虽然据说删除声明占整个执行的近48%,但这并不意味着它需要48%的时间;实际上,在查询计划的那部分内部分配的51%绝对不应被解释为占用整个操作的“一半时间”!

无论如何,按照你的说法,第一次执行表格的COUNT(*)需要几分钟时间我倾向于说你有一个与所述表/视图相关的IO问题。就个人而言,我不太喜欢物化视图,因此我对它们没有真正的经验以及它们如何在内部表现,但通常我会建议碎片导致它对底层存储系统造成损害。它第二次快速工作的原因是因为从缓存中访问页面比从磁盘中获取页面要快得多,特别是当它们遍布整个地方时。 (视图中是否有(最大)字段?)

无论如何,为了找出花了这么长时间,我建议你把这个代码从它当前所在的触发器中取出,'假'一个插入和删除的表,然后尝试再次运行查询添加时间戳和/或者使用SQL Sentry Plan Explorer之类的程序来查看每个部分真正需要多长时间(当你从程序中运行脚本时它有一个持续时间列)。 很可能你正在看错了部分;经验表明,成本和实际执行时间并不总是像我们想的那样相关。

答案 1 :(得分:1)

观察包括:

  1. 这是您正在使用的这些数据库中最大的一个吗?如果是这样,大小对优化器很重要。对于大型数据集和较小的数据集,它将制定完全不同的计划。
  2. 估计的行和实际的行非常不同。这在第四个查询中最明显。 “从@alternativeRoutes ....删除c”,其中_Security_Tuple5估计返回 16 行,但实际上使用了 235,904 行。对于那么多行,Index Scan可能比Index Seeks更高效。表格上的统计数据是最新的还是需要更新?
  3. “_Security_Tuple4中的选择计数(*)”需要几分钟,这是第一次。第二次是即时的。这是因为数据现在全部缓存在内存中(直到它老化)并且第二个查询很快。
  4. 因为问题随着数据库而移动,所以统计数据,任何缺失的索引等等都在数据库中。我还建议使用相同的模式检查索引是否与其他数据库匹配。
  5. 这不是一个完整的分析,但它给你一些东西要看。

答案 2 :(得分:0)

费奥多尔,

首先:

  

问题没有连接到特定的服务器,也没有连接到特定的SQL Server实例:如果我备份数据库然后在另一台计算机上恢复它,行为将保持不变。

我假设您:a)在隔离环境中运行此查询,b)数据未发生变异。

这是对的吗?

第二:在这里发布您的CREATE INDEX脚本。你有一个有趣的FILLFACTOR吗? SORT_IN_TEMPDB?

第三:您的ParentId,ObjectId是哪种类型? int,smallint,uniqueidentifier,varchar?