Eu tenho a seguinte definição:
CREATE TABLE [dbo].[JobItems] (
[ItemId] UNIQUEIDENTIFIER NOT NULL,
[ItemState] INT NOT NULL,
[ItemCreationTime] DATETIME NULL DEFAULT GETUTCDATE(),
[ItemPriority] TINYINT NOT NULL DEFAULT(0),
[ItemRefreshTime] DATETIME NULL,
-- lots of other columns
CONSTRAINT [PrimaryKey_GUID_HERE] PRIMARY KEY NONCLUSTERED ([ItemId] ASC)
);
CREATE UNIQUE CLUSTERED INDEX [JobItemsIndex]
ON [dbo].[JobItems]([ItemId] ASC);
CREATE INDEX [GetTaskToProcessIndex]
ON [dbo].[JobItems]([ItemState], [ItemPriority], [ItemCreationTime])
e a seguinte consulta:
SELECT TOP(1) ItemId FROM JobItems
WHERE ItemState = 5 OR
( ( ItemState = 11 ) AND ( DATEDIFF( SECOND, ItemRefreshTime, GETUTCDATE() ) > 14 ) )
ORDER BY ItemPriority ASC, ItemCreationTime ASC
Eu executo esta consulta e inspeciono o plano de execução real e aqui está o que está acontecendo:
- A busca de índice é feita para recuperar itens com
ItemState=5
. - A busca de índice é feita para recuperar itens com
ItemState=11
e, em seguida, para cada linha, uma busca separada é feita para recuperarItemRefreshTime
e os resultados de duas buscas são filtrados usando loops aninhados. - Conjuntos de 1 e 2 contendo
ItemId
,ItemCreationTime
eItemPriority
são concatenados e então... - Mágico
DistinctSort
acontece comORDER BY ItemId ASC
e finalmente TopNSort
acontece comORDER BY ItemPriority ASC, ItemCreationTime ASC
TopNSort
e DistinctSort
pegar algo como 32 por cento cada, então ficaria feliz em me livrar DistinctSort
- nem mesmo entendo seu propósito.
O que é este mágico TopNSort
que é útil DistinctSort
e por que ele está lá?
Posso reproduzir o plano que você descreve no SQL Server 2012 (no local) executando o DDL em sua pergunta e, em seguida, mexendo nas estatísticas para que o SQL Server pense que a tabela é muito maior que a realidade.
E, em seguida, executando a consulta com
OPTION (MAXDOP 1, CONCAT UNION, ORDER GROUP)
.Este é um plano de união de índice . O operador de concatenação implementa
UNION ALL
. O Distinct Sort altera a semântica para umaUNION
operação para evitar que a mesma linha seja retornada várias vezes. (No caso de a tabela não ter uma chave de índice para atuar como um identificador de linha exclusivo, o rid físico teria sido usado aqui para evitar a duplicação incorreta de diferentes linhas que possuem os mesmos valores de coluna)Um exemplo de onde isso pode ser necessário está na consulta abaixo. (observe que os dois parâmetros são definidos com o mesmo valor, portanto, um plano de união de índice buscaria as mesmas linhas duas vezes)
O Top N Sort então reclassifica os dados para implementar o
TOP 1
.No seu caso, o Distinct Sort não é logicamente necessário por vários motivos. As ramificações
ItemState = 5
eItemState = 11
são mutuamente exclusivas (e isso pode ser determinado em tempo de compilação) e, além disso, aTOP 1 ... ORDER BY ItemPriority ASC, ItemCreationTime ASC
semântica não seria afetada mesmo se houvesse duplicatas incorretas.Uma maneira alternativa de escrever a consulta (que fornece um plano melhor usando os índices para evitar qualquer classificação) é
Você pode considerar adicionar
ItemRefreshTime
uma coluna incluída ao índice para evitar a pesquisa de chave se, na prática, algumas forem necessárias antes de localizar uma única linha que satisfaça o predicado residual.