Eu tenho uma tabela como esta:
CREATE TABLE Updates
(
UpdateId INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
ObjectId INT NOT NULL
)
Rastreando essencialmente as atualizações de objetos com um ID crescente.
O consumidor desta tabela selecionará um pedaço de 100 IDs de objetos distintos, ordenados UpdateId
e iniciados a partir de um específico UpdateId
. Essencialmente, mantenha o controle de onde parou e, em seguida, consulte as atualizações.
Eu descobri que isso seja um problema de otimização interessante porque eu só fui capaz de gerar um plano de consulta máximo ideal escrevendo consultas que acontecem a fazer o que eu quero devido a índices, mas não garantir 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 distinto de fluxo , que é o que eu quero. Mas o pedido 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 pedidos.
Uma consulta que eu esperava que o SQL Server fosse inteligente o suficiente para simplificar foi 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 UpdateId
e um fluxo distinto para remover ObjectId
s duplicados . Alguma ideia?
Amostra de dados, se desejar. Os objetos raramente têm mais de uma atualização e quase nunca devem ter mais de uma em um conjunto de 100 linhas, e é por isso que estou buscando um fluxo distinto , 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 tenha mais de 100 linhas na tabela. A tabela possui mais de 1.000.000 de linhas e deve crescer rapidamente.
Suponha que o usuário tenha outra maneira de encontrar o próximo apropriado @fromUpdateId
. Não há necessidade de retorná-lo nesta consulta.