このクエリをご覧ください。それは非常に簡単です(テーブルとインデックスの定義、および再現スクリプトについては投稿の最後をご覧ください):
SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);
注:「AND 1 =(SELECT 1)は、このクエリが自動パラメータ化されないようにするためのものです。これは問題を混乱させているように感じました。
そして、これがプランです(プランのリンクを貼り付けてください):
そこには「トップ1」があるので、ストリーム集約演算子を見て驚いた。1行のみであることが保証されているので、私には必要ないようです。
その理論をテストするために、この論理的に同等のクエリを試しました。
SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;
これがその計画です(計画のリンクを貼り付けてください):
案の定、group by planは、ストリーム集約演算子なしで対応できます。
両方のクエリがインデックスの最後から「後方」を読み取り、「トップ1」を実行して最大リビジョンを取得することに注意してください。
ここで何が欠けていますか? ストリーム集合体は最初のクエリで実際に動作するのですか、それとも排除する必要がありますか(それはオプティマイザーの制限であり、そうではありません)?
ちなみに、これは信じられないほど実用的な問題ではないことを認識しています(クエリは両方ともCPUの0ミリ秒と経過時間を報告します)。
上記の2つのクエリを実行する前に実行したセットアップコードを次に示します。
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