Esta pergunta é do SO, sinalizada, mude para DBA.SE .. mas posso não ver isso acontecendo, devido a votos positivos .. então postando aqui
abaixo estão os dados de teste:
--Main Table
CREATE TABLE [dbo].[LogTable]
(
[LogID] [int] NOT NULL
IDENTITY(1, 1) ,
[DateSent] [datetime] NULL,
)
ON [PRIMARY]
GO
ALTER TABLE [dbo].[LogTable] ADD CONSTRAINT [PK_LogTable] PRIMARY KEY CLUSTERED ([LogID]) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_LogTable_DateSent] ON [dbo].[LogTable] ([DateSent] DESC) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_LogTable_DateSent_LogID] ON [dbo].[LogTable] ([DateSent] DESC) INCLUDE ([LogID]) ON [PRIMARY]
GO
--Cross table
CREATE TABLE [dbo].[LogTable_Cross]
(
[LogID] [int] NOT NULL ,
[UserID] [int] NOT NULL
)
ON [PRIMARY]
GO
ALTER TABLE [dbo].[LogTable_Cross] WITH NOCHECK ADD CONSTRAINT [FK_LogTable_Cross_LogTable] FOREIGN KEY ([LogID]) REFERENCES [dbo].[LogTable] ([LogID])
GO
CREATE NONCLUSTERED INDEX [IX_LogTable_Cross_UserID_LogID]
ON [dbo].[LogTable_Cross] ([UserID])
INCLUDE ([LogID])
GO
-- Script to populate them
INSERT INTO [LogTable]
SELECT TOP 100000
DATEADD(day, ( ABS(CHECKSUM(NEWID())) % 65530 ), 0)
FROM sys.sysobjects
CROSS JOIN sys.all_columns
INSERT INTO [LogTable_Cross]
SELECT [LogID] ,
1
FROM [LogTable]
ORDER BY NEWID()
INSERT INTO [LogTable_Cross]
SELECT [LogID] ,
2
FROM [LogTable]
ORDER BY NEWID()
INSERT INTO [LogTable_Cross]
SELECT [LogID] ,
3
FROM [LogTable]
ORDER BY NEWID()
GO
Quando usamos a consulta simples abaixo,
SELECT DI.LogID
FROM LogTable DI
INNER JOIN LogTable_Cross DP ON DP.LogID = DI.LogID
WHERE DP.UserID = 1
ORDER BY DateSent DESC
consulta mostra classificação
De acordo com meu entendimento, o custo de classificação deve ser evitado, pois temos o índice necessário
CREATE NONCLUSTERED INDEX [IX_LogTable_DateSent] ON [dbo].[LogTable] ([DateSent] DESC) ON [PRIMARY]
e também cavando no plano mostra que o mesmo índice é usado ..
Minhas perguntas são:
1.Por que o custo de classificação ainda está presente
2.O que exatamente ordered property is true
significa.
Poucas observações/trabalhos que fiz:
1.A propriedade Ordered está definida como false
então eu reescrevi a consulta como abaixo
SELECT DI.LogID
FROM LogTable DI
INNER JOIN LogTable_Cross DP ON DP.LogID = DI.LogID
WHERE DP.UserID = 1 and di.datesent is not null
ORDER BY DateSent DESC
reescrevendo como acima, torna a propriedade ordenada como verdadeira, mas ainda assim a classificação está presente
mais próximo que posso encontrar é este artigo de Paul White: A Tale of Two Index Hints ,neste artigo,o ponto abaixo esclarece por que esse tipo ocorre
Para tabelas muito grandes, o otimizador pode calcular que uma varredura orientada pelo IAM pode economizar mais tempo do que seria consumido pela classificação extra, e um plano com a varredura + classificação não ordenada seria escolhido. Esta é uma otimização heurística: o otimizador não sabe nada sobre o nível real de fragmentação de um inde
Mas essa consulta requer classificação e não deve atender às condições de uma verificação do IAM
Deixe-me saber, se você precisar de mais detalhes
Nos planos de consulta, a propriedade ordenada definida como true significa que uma verificação orientada pelo IAM não foi feita. Os dados foram lidos na ordem lógica de acordo com a definição do índice.
A junção de hash não preserva a ordem . Sua primeira consulta tem uma junção de hash, então o explícito
SORT
é necessário no final. Uma maneira de evitar a classificação na consulta é fazer uma junção de loop aninhadaLogTable
como a tabela externa. Na minha máquina, consegui fazer isso com várias dicas:Este é um plano de consulta muito ineficiente porque o índice correto não está definido na
LogTable_Cross
tabela. Uma busca é feita nessa tabela, mas apenas uma na coluna UserId:A filtragem
LogID
é feita na própria junção. Posso criar um índice que suporte melhor o plano de consulta que estou procurando:A criação desse índice não garante um plano de consulta sem classificação. O SQL Server pode estimar que um plano com uma classificação tenha um custo menor. No entanto, se eu eliminar todas as dicas, exceto a
LOOP JOIN
, recebo um plano de consulta razoavelmente eficiente sem uma classificação: