Utilisation de Microsoft SQL Server 2012 (SP3) (KB3072779) - 11.0.6020.0 (X64).
Étant donné une table et un index:
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)
Les lignes réelles pour chacune des requêtes suivantes sont de 3,1 M, les lignes estimées sont affichées sous forme de commentaires.
Lorsque ces requêtes alimentent une autre requête dans une vue , l'optimiseur choisit une jointure en boucle en raison des estimations sur 1 ligne. Comment améliorer l'estimation à ce niveau du sol pour éviter de remplacer l'indicateur de jointure de requête parent ou de recourir à un SP?
L'utilisation d'une date codée en dur fonctionne très bien:
select distinct SessionId from [User].Session -- 2.9M (great)
where CreatedUtc > '04/08/2015' -- but hardcoded
Ces requêtes équivalentes sont compatibles avec les vues, mais toutes estiment 1 ligne:
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)
Essayez quelques conseils (mais N / A pour afficher):
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);
Essayez d'utiliser Parameter / Hints (mais N / A pour afficher):
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);
Les statistiques sont à jour.
DBCC SHOW_STATISTICS('user.Session', 'IX_User_Session_CreatedUtc') with histogram;
Les dernières lignes de l'histogramme (189 lignes au total) sont affichées:
la source
>= DATEADD(DAY, -365, SYSDATETIME())
le bug est que l'estimation est basée sur>= SYSDATETIME()
. Donc, techniquement, l'estimation est basée sur le nombre de lignes du tableau qui en aurontCreatedUtc
à l'avenir. Il s'agit probablement de 0, mais SQL Server arrondit toujours 0 à 1 pour les lignes estimées.Remplacez dateadd () par dateiff () pour obtenir une approximation adéquate (30% ish).
Cela semble être un bogue similaire à MS Connect 630583 .
La recompilation des options ne fait aucune différence.
la source