Comportamiento agregado de flujo extraño

11

Consulta:

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

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

Resultado:

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

Plan de ejecución:

ingrese la descripción de la imagen aquí

La rama superior tritura el XML en cuatro filas y la rama inferior obtiene el valor del atributo ID.

Lo que me parece extraño es el número de filas devueltas por el operador Stream Aggregate. Las 2 filas que provienen del filtro son los IDatributos del primer y segundo itemnodo en el XML. Stream Aggregate devuelve cuatro filas, una para cada fila de entrada, convirtiendo efectivamente la unión interna en una unión externa.

¿Es esto algo que Stream Aggregate hace también en otras circunstancias o es algo extraño cuando se realizan consultas XML?

No puedo ver ninguna pista en la versión XML del plan de consulta de que este Agregado de Stream debería comportarse de manera diferente a cualquier otro Agregado de Stream que haya notado antes.

Mikael Eriksson
fuente

Respuestas:

13

El agregado es un agregado escalar (sin grupo por cláusula). Estos están definidos en SQL Server para producir siempre una fila, incluso si la entrada está vacía.

Para un agregado escalar , MAXsin filas es NULL, COUNTsin filas es cero, por ejemplo. El optimizador lo sabe todo y puede transformar una unión externa en una interna en circunstancias adecuadas.

-- 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 ();

Para obtener más información sobre los agregados, consulte mi artículo Diversión con agregados escalares y vectoriales .

Paul White 9
fuente
10

Lo que hay que recordar aquí es que los planes de ejecución absorben los datos.

Entonces, el operador de Nested Loop llama a Stream Aggregate 4 veces. Stream Aggregate también llama al filtro 4 veces, pero solo obtiene un valor dos veces.

Entonces Stream Aggregate da cuatro valores. Dos veces da un valor, y dos veces da Nulo.

Rob Farley
fuente