Consultez cette requête. C'est assez simple (voir la fin de l'article pour les définitions de table et d'index, et un script de repro):
SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);
Remarque: le "AND 1 = (SELECT 1) est juste pour empêcher cette requête d'être auto-paramétrée, ce qui, je le pensais, prêtait à confusion - il obtient en fait le même plan avec ou sans cette clause
Et voici le plan ( collez le lien du plan) :
Puisqu'il y a un "top 1", j'ai été surpris de voir l'opérateur d'agrégat de flux. Cela ne me semble pas nécessaire, car il ne peut y avoir qu'une seule ligne.
Pour tester cette théorie, j'ai essayé cette requête logiquement équivalente:
SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;
Voici le plan pour celui-ci ( collez le lien du plan ):
Effectivement, le plan groupé peut s'en tirer sans l'opérateur d'agrégat de flux.
Notez que les deux requêtes lisent "en arrière" à partir de la fin de l'index et font un "top 1" pour obtenir la révision maximale.
Qu'est-ce que j'oublie ici? L'agrégat de flux fonctionne-t-il réellement dans la première requête, ou devrait-il être éliminé (et c'est juste une limitation de l'optimiseur que ce n'est pas le cas)?
Soit dit en passant, je me rends compte que ce n'est pas un problème incroyablement pratique (les deux requêtes rapportent 0 ms de CPU et le temps écoulé), je suis juste curieux de savoir les internes / comportements présentés ici.
Voici le code d'installation que j'ai exécuté avant d'exécuter les deux requêtes ci-dessus:
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