将索引添加到 CTE

Posted

技术标签:

【中文标题】将索引添加到 CTE【英文标题】:Adding an INDEX to a CTE 【发布时间】:2011-04-29 02:23:14 【问题描述】:

我可以向公用表表达式 (CTE) 添加 INDEX 吗?

【问题讨论】:

这可能与一些计划指南有关。 This article by Quassnoi 展示了如何使用计划指南通过将 EagerSpool 添加到计划中来获取缓存的 CTE 结果。这会在 tempdb 中为它们建立一个临时索引。 【参考方案1】:

没有。

CTE 是一个临时的“内联”视图 - 您不能向此类结构添加索引。

如果您需要索引,请使用 CTE 的 SELECT 创建一个常规视图,并使其成为索引视图(通过向视图添加聚集索引)。您需要遵守此处列出的一组规则:Creating an Indexed View。

【讨论】:

对我来说,索引视图第一次尝试用了 18 秒,然后是 16 秒,第三次尝试用了 14 秒。 CTE 首次尝试耗时 16 秒。我会坚持使用 CTE。顺便说一句,对我来说,索引表(暂时使用)是最好的,总体上缩短到 10 秒。【参考方案2】:

我也有同样的要求。不能将索引添加到 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

【讨论】:

你在哪里学的这种巫术?它对我们的长时间运行的查询有显着的影响。 Top 100000 比 Top 100 PERCENT 效果更好。我将开始深入研究查询分析器,看看发生了什么。谢谢! 当您在 CTE 选择中说的时候,您是指创建 CTE 的选择,还是使用 CTE 的选择? 我一直很想知道这些技术,你能举个例子来证明thanx 很难举出一个对你有意义的例子,因为你需要对大量数据集执行才能看到价值。我将寻找给我带来这种好处的查询,并在接下来的几天内更详细地记录结果和性能改进。 @BlackjacketMack:“巫毒”。回想起来,在 CTE 中使用 ORDER BY 的错误消息非常清楚:'ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效,除非还指定了 TOP、OFFSET 或 FOR XML 。但对理查德的回答表示敬意。我的 CTE 需要 DISTINCT,所以 TOP 100 PERCENT 不起作用。这种作弊方法始终可用:ORDER BY [Blah] OFFSET 0 ROWS【参考方案3】:

您不能索引 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 上的索引。

【讨论】:

【参考方案4】:

另一种技术是插入临时表而不是使用 CTE 然后您可以向临时表添加索引

通过这样做,我将 9 分钟的查询缩短为 3 秒的查询。

有些人可能在宗教上反对临时表。如果是你,请随意点击投反对票!

对于我们其他试图让事情顺利进行的人......需要考虑的事情。

(我确实尝试了前 100000 名...排序)我没有意识到时间减少。

【讨论】:

我现在正在尝试这个,我在这件事上没有任何宗教信仰!这是一个非常复杂的 CTE,有多个部分,所以我想我可能需要将它分解为不同的过程,一个用于填充 tmp 表,另一个用于在下半部分读取它。很高兴听到您的成功。

以上是关于将索引添加到 CTE的主要内容,如果未能解决你的问题,请参考以下文章

添加包含上一级父级的 cte 列

CTE内部有多个子查询

使用 cte ROW_NUMBER() 提高性能

带有子查询的 CTE 查询在小型索引表上很慢;如何在 MySQL 上进行优化?

将起始索引添加到字符串索引生成器

将 MySQL 索引添加到大表的性能影响