Comportamento agregado de fluxo ímpar

11

Inquerir:

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

Plano de execução:

insira a descrição da imagem aqui

A ramificação superior fragmenta o XML em quatro linhas e a ramificação inferior busca o valor do atributo ID.

O que me parece estranho é o número de linhas retornadas do operador Stream Aggregate. As 2 linhas que vêm do filtro são o IDatributo do primeiro e do segundo itemnós no XML. O Stream Aggregate retorna quatro linhas, uma para cada linha de entrada, transformando efetivamente a junção interna em uma junção externa.

Isso também é algo que o Stream Aggregate faz em outras circunstâncias ou é algo estranho acontecendo ao fazer consultas XML?

Não vejo nenhuma dica na versão XML do plano de consulta de que este Stream Aggregate deve se comportar de maneira diferente de qualquer outro Stream Aggregate que eu tenha notado antes.

Mikael Eriksson
fonte

Respostas:

13

O agregado é um agregado escalar (sem agrupar por cláusula). Eles são definidos no SQL Server para sempre produzir uma linha, mesmo se a entrada estiver vazia.

Para um agregado escalar , MAXsem linhas é NULL, COUNTsem linhas é zero, por exemplo. O otimizador sabe tudo sobre isso e pode transformar uma junção externa em uma junção interna em circunstâncias adequadas.

-- 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 saber mais sobre agregados, consulte meu artigo Diversão com agregados escalares e vetoriais .

Paul White 9
fonte
10

É importante lembrar que os planos de execução sugam os dados.

Portanto, o operador Nested Loop chama o Stream Aggregate 4 vezes. O Stream Aggregate também chama o filtro 4 vezes, mas obtém um valor apenas duas vezes.

Portanto, o Stream Aggregate fornece quatro valores. Dá duas vezes um valor e duas vezes dá Nulo.

Rob Farley
fonte