为什么需要汇总此流?


12

查看此查询。这非常简单(有关表和索引的定义以及repro脚本,请参见文章结尾):

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);

注意:“ AND 1 =(SELECT 1)只是为了防止此查询被自动参数化,我觉得这使问题感到困惑-尽管有或没有该子句,它实际上都得到相同的计划

这是计划(粘贴计划链接)

用流聚合计划

由于那里有一个“ top 1”,我很惊讶地看到流聚合运算符。对我来说似乎没有必要,因为保证只有一行。

为了检验该理论,我尝试了这个逻辑上等效的查询:

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;

这是该计划(粘贴计划链接):

没有流的计划

果然,按计划分组无需流聚合运算符就可以通过。

请注意,两个查询均从索引末尾读取“向后”,并执行“ top 1”以获取最大修订。

我在这里想念什么? 流聚合实际上是在第一个查询中进行工作,还是应该将其消除(这不是优化器的限制,而并非如此)?

顺便说一句,我意识到这不是一个非常实际的问题(两个查询都报告了0 ms的CPU和经过的时间),我只是好奇这里展示的内部/行为。


这是我在运行上述两个查询之前运行的设置代码:

DROP TABLE IF EXISTS dbo.TheOneders;
GO

CREATE TABLE dbo.TheOneders
(
    Id INT NOT NULL,
    Revision SMALLINT NOT NULL,
    Something NVARCHAR(23),

    CONSTRAINT PK_TheOneders PRIMARY KEY NONCLUSTERED (Id, Revision)
);
GO

INSERT INTO dbo.TheOneders
    (Id, Revision, Something)
SELECT DISTINCT TOP 1000 
    1, m.message_id, 'Do...'
FROM sys.messages m
ORDER BY m.message_id
OPTION (MAXDOP 1);

INSERT INTO dbo.TheOneders
    (Id, Revision, Something)
SELECT DISTINCT TOP 100 
    2, m.message_id, 'Do that thing you do...'
FROM sys.messages m
ORDER BY m.message_id
OPTION (MAXDOP 1);
GO

Answers:


16

如果没有行与该WHERE子句匹配,则可以看到此聚合的作用。

SELECT MAX(Revision)
FROM   dbo.TheOneders
WHERE  Id = 1
       AND 1 = 1 /*To avoid auto parameterisation*/
       AND Id%3 = 4  /*always false*/

在那种情况下,零行进入了聚合,但它仍然发出一行,因为NULL在这种情况下要返回正确的语义。

在此处输入图片说明

这是标量集合,而不是向量1。

您的“逻辑等效”查询不等效。添加GROUP BY Id将使其成为向量聚合,然后正确的行为将是不返回任何行。

有关更多信息,请参见“ 与标量和矢量聚合一起使用”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.