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.