我试图找出 MS CTE 实际上如何访问数据。尝试找出 CTE 在提取数据时是否实际上会运行得更慢,以及 CTE 提取数据的顺序是什么。CTE 是在调用视图时提取数据还是在创建结果集时的最后一个 select 语句中提取数据?CTE 需要多久调用一次数据库来获取额外数据?
公共表表达式和临时对象之间的主要区别在于CTE 不会具体化结果集,并且每次引用它们时都需要重新执行内部查询。我不会将@table 变量引入其中,因为它会带来额外的性能复杂性。
我使用这个演示作为便携式示例。这里不存在性能问题,因为它是单行表,但足以表达要点。
CREATE TABLE
#t
(
id int NOT NULL PRIMARY KEY
);
INSERT
#t
(
id
)
SELECT
id = 1;
Run Code Online (Sandbox Code Playgroud)
我们有一个单行表,现在让我们用 CTE 来处理它:
WITH
t AS
(
SELECT
t.id
FROM #t AS t
)
SELECT
t.*
FROM t
JOIN t AS t2
ON t2.id = t.id
JOIN t AS t3
ON t3.id = t.id;
Run Code Online (Sandbox Code Playgroud)
生成的查询计划如下所示:
对于公共表表达式的每个连接,我们最终都会访问基表。如果您的 CTE 被多次引用,通常最好使用 #temp 表来具体化结果。在包含更复杂查询的公共表表达式中,这可能特别痛苦。
虽然行目标不会具体化公共表表达式结果,但它们(至少到 SQL Server 的当前版本)确实为其中的查询提供了优化栅栏。
作为其工作原理的示例,请看一下这两个查询:
SELECT
c = COUNT_BIG(*)
FROM dbo.Users AS u
JOIN dbo.Posts AS p
ON p.OwnerUserId = u.AccountId
JOIN dbo.Comments AS c
ON c.PostId = p.ParentId
JOIN dbo.Votes AS v
ON v.PostId = c.PostId
WHERE c.Score > 1000;
SELECT
c = COUNT_BIG(*)
FROM dbo.Users AS u
JOIN dbo.Posts AS p
ON p.OwnerUserId = u.AccountId
JOIN
(
SELECT TOP (2147483647)
c.*
FROM dbo.Comments AS c
JOIN dbo.Votes AS v
ON v.PostId = c.PostId
WHERE c.Score > 1000
) AS c ON c.PostId = p.ParentId;
Run Code Online (Sandbox Code Playgroud)
以下是它们的查询计划:
由于 SQL Server 必须遵守TOP 运算符设置的行目标,因此连接顺序发生了变化。这里没有真正的性能差异,但您明白了。如果您想一起发生一件特定的事情,这可能是实现这一目标的一种方法,无需临时对象,但无需具体化。
有关通过使用 #temp 表来调整滥用 Common Table 表达式的查询的示例,请查看我的这篇文章:
那里有一个视频,我无法在此处嵌入该视频,该视频逐步识别诸如公共表表达式中的不良基数估计之类的内容,并将每个视频用作实现结果的停止点。
| 归档时间: |
|
| 查看次数: |
740 次 |
| 最近记录: |