我一直在尝试以下(简化)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
这是从使用表变量时开始的。该查询运行时间超过17分钟:
XML格式的执行计划
临时表:https://docs.google.com/open?id=0B66I-fxlyEtEZEthV3ZaWlNLWXM
表变量:https://docs.google.com/open?id=0B66I-fxlyEtEbUFZa3RJejFCTkk
答案 0 :(得分:4)
查询计划明确指出,表变量版本正遭受臭名昭着的“表变量基数估计”问题。这主要是因为与临时表不同,表变量不支持统计信息。 Paul White撰写的这篇文章详细解释了它:
https://sqlkiwi.blogspot.com/2012/08/temporary-tables-in-stored-procedures.html
同样明确的是,最简单的解决方案可能是在查询结尾添加OPTION (Recompile);
子句。虽然这在早期版本的SQL Server中可能不起作用,但在更高版本中,它应该使它获得更好的基数估计,从而产生与临时表版本相同的查询计划。
如果这不起作用,请告诉我,因为还有一些其他(不太理想的)可能的解决方案。
答案 1 :(得分:0)
部分解决方案:使用“索引物理统计”报告按照SQL Server的建议重建或重新组织表上的索引有很大帮助。右键单击数据库&gt;可以使用此报告。报告&gt;标准报告&gt;索引物理统计。