Considere estas consultas ( SQL Fiddle ):
Consulta 1:
SELECT * INTO #TMP1 FROM Foo
UNION
SELECT * FROM Boo
UNION
SELECT * FROM Koo;
Consulta 2:
SELECT * INTO #TMP2 FROM Foo
UNION
SELECT * FROM Boo
UNION ALL
SELECT * FROM Koo;
Observe que Koo não se sobrepõe a Boo/Foo, então o resultado final é o mesmo. A questão é por que a primeira combinação UNION / UNION não é mesclada em uma única operação SORT?
O otimizador de consulta possui operadores n-ários, embora o mecanismo de execução tenha um número bem menor. Para ilustrar, vou usar uma versão simplificada de suas tabelas - (SQL Fiddle) .
Dadas essas tabelas e dados, vamos olhar para a árvore de entrada para uma
UNION
consulta de três vias:O operador de união lógica tem uma saída e três entradas filhas. Após a otimização baseada em custo, a árvore física escolhida é uma união de mesclagem com três entradas:
A saída do otimizador é retrabalhada em uma forma que o mecanismo de execução (sem união de mesclagem n-ária) pode manipular:
A reescrita pós-otimização desdobra o n-ário
PhyOp_MergeUnion
em vários operadores Merge Union. Observe como todo o custo estimado permanece associado ao operador de união 'original' - os outros têm uma estimativa de custo zero.O fato de o otimizador raciocinar sobre uniões usando operadores n-ários fornece uma explicação de por que ele não considera reescrever seu primeiro exemplo para o mesmo plano do segundo exemplo (a união de três vias é um único nó de árvore).
A segunda razão é que não há restrições para impor a 'falta de sobreposição'. Antes que as restrições estejam em vigor, uma união entre
boo
ekoo
não pode ser garantida para não produzir duplicatas, portanto, obtemos um plano de remoção de duplicatas (uma união de mesclagem neste caso):Adicionar as seguintes restrições garante que a condição de não sobreposição não possa ser violada sem invalidar os planos em cache para a consulta:
Agora é seguro para o otimizador simplesmente concatenar:
No entanto, mesmo com essas restrições em vigor, a consulta de união de três vias ainda aparece como três uniões porque o otimizador normalmente não considera a divisão de operadores n-ários para explorar alternativas. O operador n-ário é muito útil para manter o espaço de busca sob controle; separá-lo muitas vezes seria contraproducente devido ao objetivo do otimizador de encontrar um bom plano rapidamente.
Quando escrito como a
UNION
eUNION ALL
, um operador n-ário não pode mais ser usado (os tipos não correspondem), então a árvore tem nós separados:O SQL Server possui operações de conjunto de 3 vias; o operador CONCATENATION aceita n entradas. Dadas, por exemplo, dez tabelas:
e uma consulta que une tudo para encontrar qualquer linha em cada tabela que tenha a mesma chave:
Veremos um plano de consulta que obtém as linhas correspondentes (com push down do predicado no operador TABLE SCAN) e concatena todos os resultados no
SELECT
operador.A razão pela qual você não obtém um plano mesclado e depois classificado é porque seria muito lento e a classificação não é necessária para implementar a
UNION
operação. Nas tabelas BOO, FOO e KOO, você declarou uma chave primária. Quando o acessador CLUSTERED INDEX SCAN enumera as linhas, elas são produzidas na ordem do índice clusterizado subjacente -- garantido. Concatenar dois conjuntos e, em seguida, classificar o resultado é muito mais lento do que usar o operador MERGE JOIN, e o operador MJ pode ser usado com muita facilidade, pois ambos os conjuntos são classificados e indexados.