【问题标题】:Common Table Expressions slow when using a table variable使用表变量时,公用表表达式变慢
【发布时间】:2012-10-22 14:34:56
【问题描述】:

我一直在试验以下(简化的)CTE。使用表变量 () 时,查询会在我取消之前运行几分钟。任何其他被注释掉的方法都会在不到一秒的时间内返回。

如果我用 INNER JOIN 替换整个 WHERE 子句,它也很快。

任何想法为什么使用表变量会运行这么慢?

FWIW:数据库包含 250 万条记录,内部查询返回 2 条记录。

CREATE TABLE #rootTempTable (RootID int PRIMARY KEY)
INSERT INTO #rootTempTable VALUES (1360);

DECLARE @rootTableVar TABLE (RootID int PRIMARY KEY);
INSERT INTO @rootTableVar VALUES (1360);

WITH My_CTE AS 
(
      SELECT ROW_NUMBER() OVER(ORDER BY d.DocumentID) rownum, d.DocumentID, d.Title
      FROM [Document] d
      WHERE d.LocationID IN 
        (
              SELECT LocationID 
              FROM Location 
                    JOIN @rootTableVar rtv ON Location.RootID = rtv.RootID -- VERY SLOW!
                    --JOIN #rootTempTable tt ON Location.RootID = tt.RootID -- Fast
                    --JOIN (SELECT 1360 as RootID) AS rt ON Location.RootID = rt.RootID -- Fast
                    --WHERE RootID = 1360 -- Fast
        )           
) 
SELECT * FROM My_CTE WHERE (rownum > 0) AND (rownum <= 100) ORDER BY rownum

这是从使用 table 变量时开始的。查询运行时间超过 17 分钟:

XML 格式的执行计划

临时表:https://docs.google.com/open?id=0B66I-fxlyEtEZEthV3ZaWlNLWXM

表变量:https://docs.google.com/open?id=0B66I-fxlyEtEbUFZa3RJejFCTkk

【问题讨论】:

  • 发布表变量和临时表版本的查询计划。
  • 这实际上是我第一次在表变量中看到主键。我很好奇 - 执行计划有什么要说的?
  • 我让表变量版本运行完成:17m 41s。您希望执行计划的任何特定格式?顺便说一句 - 主键只是我正在玩的东西,看看它是否会有所作为。好像没有。
  • 请以 XML 格式发布执行计划。如果可能,作为文件共享的链接(例如 DropBox 或 google docs)。
  • 不要忘记#temp 表版本。我们需要它们进行比较。

标签: sql-server common-table-expression table-variable


【解决方案1】:

查询计划清楚地表明,表变量版本正遭受臭名昭著的“表变量基数估计”问题。这主要是因为与临时表不同,表变量不支持统计信息。 Paul White 的这篇文章详细解释了它:

https://sqlkiwi.blogspot.com/2012/08/temporary-tables-in-stored-procedures.html

同样清楚的是,最简单的解决方案可能是在查询末尾添加一个OPTION (Recompile); 子句。虽然这在 SQL Server 的早期版本中可能不起作用,但在更高版本中它应该会使其获得更好的基数估计,从而生成与临时表版本相同的查询计划。

如果这不起作用,请告诉我,因为还有其他一些(不太理想的)可能的解决方案。

【讨论】:

  • 谢谢 - 一个很好的建议。但是,似乎我只能在外部 SELECT (而不是 CTE 内)之后添加它,它似乎没有太大区别。最后,我重建/重组了索引,这在一定程度上有所帮助,并且我还在寻找不使用 CTE 的替代查询。
【解决方案2】:

部分解决方案:帮助很大的是按照 SQL Server 的建议,使用索引物理统计报告重建或重组表上的索引。此报告可通过右键单击数据库 > 报告 > 标准报告 > 索引物理统计来获得。

【讨论】:

    猜你喜欢
    • 2021-09-08
    • 2021-05-22
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多