Tenho uma tabela assim:
CREATE TABLE Updates
(
UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
ObjectId INT NOT NULL
)
Essencialmente, rastreando atualizações de objetos com um ID crescente.
O consumidor desta tabela selecionará um bloco de 100 IDs de objetos distintos, ordenados por UpdateId
e a partir de um UpdateId
. Essencialmente, mantendo o controle de onde parou e, em seguida, consultando as atualizações.
Descobri que isso é um problema de otimização interessante porque só consegui gerar um plano de consulta maximamente ideal escrevendo consultas que fazem o que eu quero devido aos índices, mas não garantem o que eu quero:
SELECT DISTINCT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
Onde @fromUpdateId
é um parâmetro de procedimento armazenado.
Com um plano de:
SELECT <- TOP <- Hash match (flow distinct, 100 rows touched) <- Index seek
Devido à busca no UpdateId
índice que está sendo usado, os resultados já são bons e ordenados do menor para o maior ID de atualização, como eu quero. E isso gera um plano de fluxo distinto , que é o que eu quero. Mas o ordenamento obviamente não é um comportamento garantido, então não quero usá-lo.
Esse truque também resulta no mesmo plano de consulta (embora com um TOP redundante):
WITH ids AS
(
SELECT ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
ORDER BY UpdateId OFFSET 0 ROWS
)
SELECT DISTINCT TOP 100 ObjectId FROM ids
No entanto, não tenho certeza (e suspeito que não) se isso realmente garante o pedido.
Uma consulta que eu esperava que o SQL Server fosse inteligente o suficiente para simplificar era essa, mas acaba gerando um plano de consulta muito ruim:
SELECT TOP 100 ObjectId
FROM Updates
WHERE UpdateId > @fromUpdateId
GROUP BY ObjectId
ORDER BY MIN(UpdateId)
Com um plano de:
SELECT <- Top N Sort <- Hash Match aggregate (50,000+ rows touched) <- Index Seek
Estou tentando encontrar uma maneira de gerar um plano ideal com uma busca de índice ativada UpdateId
e um fluxo distinto para remover ObjectId
s duplicados. Alguma ideia?
Dados de amostra, se você quiser. Os objetos raramente terão mais de uma atualização e quase nunca devem ter mais de uma em um conjunto de 100 linhas, e é por isso que estou atrás de um fluxo distinct , a menos que haja algo melhor que eu não conheça? No entanto, não há garantia de que um único ObjectId
não terá mais de 100 linhas na tabela. A tabela tem mais de 1.000.000 de linhas e espera-se que cresça rapidamente.
Suponha que o usuário deste tenha outra maneira de encontrar o próximo apropriado @fromUpdateId
. Não há necessidade de devolvê-lo nesta consulta.