Comportement d'agrégat de flux impair

11

Requete:

declare @X xml = '
<item ID = "0"/>
<item ID = "1"/>
<item/>
<item/>';

select I.X.value('@ID', 'int')
from @X.nodes('/item') as I(X);

Résultat:

-----------
0
1
NULL
NULL

Plan d'exécution:

entrez la description de l'image ici

La branche supérieure déchiquette le XML en quatre lignes et la branche inférieure récupère la valeur de l'attribut ID.

Ce qui me semble étrange, c'est le nombre de lignes renvoyées par l'opérateur Stream Aggregate. Les 2 lignes qui proviennent du filtre sont l' IDattribut des premier et deuxième itemnœuds du XML. Le Stream Aggregate renvoie quatre lignes, une pour chaque ligne d'entrée, transformant ainsi la jointure interne en jointure externe.

Est-ce quelque chose que Stream Aggregate fait également dans d'autres circonstances ou est-ce juste quelque chose d'étrange qui se produit lors des requêtes XML?

Je ne vois aucun indice dans la version XML du plan de requête selon lequel cet agrégat de flux devrait se comporter différemment de tout autre agrégat de flux que j'ai remarqué auparavant.

Mikael Eriksson
la source

Réponses:

13

L'agrégat est un agrégat scalaire (pas de clause group by). Celles-ci sont définies dans SQL Server pour toujours produire une ligne, même si l'entrée est vide.

Pour un agrégat scalaire , MAXaucune ligne n'est NULL, COUNTaucune ligne est zéro, par exemple. L'optimiseur sait tout cela et peut transformer une jointure externe en jointure interne dans des circonstances appropriées.

-- NULL for a scalar aggregate
SELECT MAX(V.v) FROM (VALUES(1)) AS V (v) WHERE V.v = 2;

-- No row for a vector aggregate
SELECT MAX(V.v) FROM (VALUES(1)) AS V (v) WHERE V.v = 2 GROUP BY ();

Pour en savoir plus sur les agrégats, consultez mon article Fun With Scalar and Vector Aggregates .

Paul White 9
la source
10

La chose à retenir ici est que les plans d'exécution aspirent les données.

L'opérateur de boucle imbriquée appelle donc le Stream Aggregate 4 fois. Le Stream Aggregate appelle également le filtre 4 fois, mais n'obtient une valeur que deux fois.

Le Stream Aggregate donne donc quatre valeurs. Deux fois, cela donne une valeur, et deux fois, cela donne Null.

Rob Farley
la source