Usando o Microsoft SQL Server 2012 (SP3) (KB3072779) - 11.0.6020.0 (X64).
Dada uma tabela e um índice:
create table [User].[Session]
(
SessionId int identity(1, 1) not null primary key
CreatedUtc datetime2(7) not null default sysutcdatetime())
)
create nonclustered index [IX_User_Session_CreatedUtc]
on [User].[Session]([CreatedUtc]) include (SessionId)
As linhas reais para cada uma das consultas a seguir são de 3,1 milhões; as linhas estimadas são mostradas como comentários.
Quando essas consultas alimentam outra consulta em uma Visualização , o otimizador escolhe uma junção de loop devido às estimativas de 1 linha. Como melhorar a estimativa nesse nível do solo para evitar substituir a dica de junção da consulta pai ou recorrer a um SP?
Usar uma data codificada funciona muito bem:
select distinct SessionId from [User].Session -- 2.9M (great)
where CreatedUtc > '04/08/2015' -- but hardcoded
Essas consultas equivalentes são compatíveis com visualização, mas todas estimam uma linha:
select distinct SessionId from [User].Session -- 1
where CreatedUtc > dateadd(day, -365, sysutcdatetime())
select distinct SessionId from [User].Session -- 1
where dateadd(day, 365, CreatedUtc) > sysutcdatetime();
select distinct SessionId from [User].Session s -- 1
inner loop join (select dateadd(day, -365, sysutcdatetime()) as MinCreatedUtc) d
on d.MinCreatedUtc < s.CreatedUtc
-- (also tried reversing join order, not shown, no change)
select distinct SessionId from [User].Session s -- 1
cross apply (select dateadd(day, -365, sysutcdatetime()) as MinCreatedUtc) d
where d.MinCreatedUtc < s.CreatedUtc
-- (also tried reversing join order, not shown, no change)
Tente algumas dicas (mas N / D para exibir):
select distinct SessionId from [User].Session -- 1
where CreatedUtc > dateadd(day, -365, sysutcdatetime())
option (recompile);
select distinct SessionId from [User].Session -- 1
where CreatedUtc > (select dateadd(day, -365, sysutcdatetime()))
option (recompile, optimize for unknown);
select distinct SessionId -- 1
from (select dateadd(day, -365, sysutcdatetime()) as MinCreatedUtc) d
inner loop join [User].Session s
on s.CreatedUtc > d.MinCreatedUtc
option (recompile);
Tente usar Parâmetro / Dicas (mas N / D para exibir):
declare
@minDate datetime2(7) = dateadd(day, -365, sysutcdatetime());
select distinct SessionId from [User].Session -- 1.2M (adequate)
where CreatedUtc > @minDate;
select distinct SessionId from [User].Session -- 2.96M (great)
where CreatedUtc > @minDate
option (recompile);
select distinct SessionId from [User].Session -- 1.2M (adequate)
where CreatedUtc > @minDate
option (optimize for unknown);
As estatísticas estão atualizadas.
DBCC SHOW_STATISTICS('user.Session', 'IX_User_Session_CreatedUtc') with histogram;
As últimas linhas do histograma (total de 189 linhas) são mostradas:
fonte
>= DATEADD(DAY, -365, SYSDATETIME())
o erro é que a estimativa é baseada>= SYSDATETIME()
. Portanto, tecnicamente, a estimativa é baseada em quantas linhas na tabela existemCreatedUtc
no futuro. Provavelmente, é 0, mas o SQL Server sempre arredonda de 0 a 1 para as linhas estimadas.Substitua dateadd () por datediff () para obter uma aproximação adequada (30% ish).
Este parece ser um bug semelhante ao MS Connect 630583 .
A opção recompilar não faz diferença.
fonte