Tenho uma consulta muito simples em que uso um UNION ALL
+ ORDER BY
em duas consultas que retornam dados pré-ordenados de seus respectivos índices. Por algum motivo, o SQL não usa um Merge Join (Concatenation)
para isso, mas um Concatenation
, seguido por um Sort
. Qual poderia ser o motivo?
Aqui está um exemplo completo de reprodução. (As INDEX
dicas são necessárias para que o SQL Server use o índice, apesar do baixo número de linhas na tabela.)
CREATE TABLE T1(
SequenceNumber bigint IDENTITY NOT NULL,
TenantId uniqueidentifier NOT NULL,
Object1Id uniqueidentifier NOT NULL,
Payload nvarchar(max) NOT NULL,
OtherNumber bigint NOT NULL,
CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED (TenantId,SequenceNumber ASC)
)
CREATE INDEX IX_TenantId_Object1Id_OtherNumber ON T1(TenantId, Object1Id, OtherNumber)
CREATE TABLE T2(
SequenceNumber bigint IDENTITY NOT NULL,
TenantId uniqueidentifier NOT NULL,
Object2Id uniqueidentifier NOT NULL,
Payload nvarchar(max) NOT NULL,
OtherNumber bigint NOT NULL,
CONSTRAINT PK_T2 PRIMARY KEY CLUSTERED (TenantId,SequenceNumber ASC)
)
CREATE INDEX IX_TenantId_Object2Id_OtherNumber ON T2(TenantId, Object2Id, OtherNumber)
DECLARE @tenantId UNIQUEIDENTIFIER = NEWID()
DECLARE @object1Id UNIQUEIDENTIFIER = NEWID()
DECLARE @object2Id UNIQUEIDENTIFIER = NEWID()
SELECT OtherNumber, Payload FROM T1 WITH (INDEX(IX_TenantId_Object1Id_OtherNumber)) WHERE TenantId = @tenantId AND Object1Id = @object1Id
UNION ALL
SELECT OtherNumber, Payload FROM T2 WITH (INDEX(IX_TenantId_Object2Id_OtherNumber)) WHERE TenantId = @tenantId AND Object2Id = @object2Id
ORDER BY OtherNumber
DROP TABLE T1
DROP TABLE T2
E esta é uma captura de tela do plano de execução:
Quando adiciono a MERGE UNION
opção, o SQL Server pré-classifica explicitamente os resultados individuais da consulta (em OtherNumber
e Payload
, por algum motivo).
Agora, uma reviravolta interessante: quando adiciono uma restrição UNIQUE às OtherNumber
colunas, o SQL Server repentinamente escolhe o Merge Join (Concatenation)
operador. Por quê?
Testei isso localmente no SQL Server 2016 e no Azure SQL.
Isso é essencialmente respondido por Ordem e natureza das colunas na lista de seleção da consulta UNION classificada afeta o desempenho , que se vincula à explicação completa e complicada no meu artigo, Evitando classificações com concatenação de junção de mesclagem .
O principal ponto a ser considerado é que o otimizador de consultas do SQL Server não realiza uma busca exaustiva das estratégias disponíveis para evitar ordenações. Esta é uma decisão pragmática, pois o espaço de busca cresce rapidamente.
Como resultado, às vezes você verá uma classificação evitável em um plano de execução. Existe um método para determinar como o SQL Server atualmente deriva os requisitos de classificação para Concatenação de Mesclagem e como ele pode, às vezes, tomar atalhos (dado um índice ou restrição exclusivos, por exemplo). Ainda assim, isso é observacional; não há garantias comportamentais publicadas.
Nesse sentido, a resposta para esse tipo de pergunta é sempre a mesma e envolve seguir a lógica utilizada pelo otimizador.
A resposta para o seu tipo específico da mesma questão subjacente é abordada na seção do meu artigo, Problemas com índices não exclusivos :
Fornecendo mais uma ilustração para cobrir a importância da lista de projeções:
Adicionar SequenceNumber ao início da lista de projeção resultou na simplificação do requisito de classificação devido às chaves (primárias) em ( TenantId,SequenceNumber ), com TenantId restrito a um único valor pelo predicado de igualdade em sua consulta.