【发布时间】:2011-04-29 02:23:14
【问题描述】:
我可以向公用表表达式 (CTE) 添加 INDEX 吗?
【问题讨论】:
-
这可能与一些计划指南有关。 This article by Quassnoi 展示了如何使用计划指南通过将 EagerSpool 添加到计划中来获取缓存的 CTE 结果。这会在 tempdb 中为它们建立一个临时索引。
标签: sql-server-2008 common-table-expression
我可以向公用表表达式 (CTE) 添加 INDEX 吗?
【问题讨论】:
标签: sql-server-2008 common-table-expression
没有。
CTE 是一个临时的“内联”视图 - 您不能向此类结构添加索引。
如果您需要索引,请使用 CTE 的 SELECT 创建一个常规视图,并使其成为索引视图(通过向视图添加聚集索引)。您需要遵守此处列出的一组规则:Creating an Indexed View。
【讨论】:
我也有同样的要求。不能将索引添加到 CTE。但是,在 CTE 选择中,在连接字段上添加 ORDER BY 子句将执行时间从 20 分钟或更长时间减少到 10 秒以下。
(您还需要添加 SELECT TOP 100 PERCENT 以允许在 CTE 选择中使用 ORDER BY。)
[编辑以添加下面评论中的释义引述]:
如果您在 CTE 中有 DISTINCT,则 TOP 100 PERCENT 不起作用。这种作弊方法始终可用:在 select 中根本不需要 TOP,将 ORDER BY 语句更改为:
ORDER BY [Blah] OFFSET 0 ROWS
【讨论】:
您不能索引 CTE,但方法是 CTE 可以利用基础索引。
WITH cte AS (
SELECT myname, SUM(Qty) FROM t GROUP BY myname
)
SELECT *
FROM t a JOIN cte b ON a.myname=b.myname
在上述查询中,a JOIN b 无法使用 t.myname 上的索引,因为 GROUP BY。
另一方面,
WITH cte AS (
SELECT myname, SUM(Qty) OVER (PARTITION BY myname) AS SumQty,
ROW_NUMBER() OVER (PARTITION BY myname ORDER BY myname, Qty) AS n
)
SELECT * FROM t a JOIN cte b ON a.myname=b.myname AND b.n=1
在后一个查询中,a JOIN b 可以使用t.myname 上的索引。
【讨论】:
另一种技术是插入临时表而不是使用 CTE 然后您可以向临时表添加索引
通过这样做,我将 9 分钟的查询缩短为 3 秒的查询。
有些人可能在宗教上反对临时表。如果是你,请随意点击投反对票!
对于我们其他试图让事情顺利进行的人......需要考虑的事情。
(我确实尝试了前 100000 名...排序)我没有意识到时间减少。
【讨论】: