Verwenden von Microsoft SQL Server 2012 (SP3) (KB3072779) - 11.0.6020.0 (X64).
Gegeben eine Tabelle und einen 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)
Die tatsächlichen Zeilen für jede der folgenden Abfragen betragen 3,1 Millionen. Die geschätzten Zeilen werden als Kommentare angezeigt.
Wenn diese Abfragen eine andere Abfrage in einer Ansicht füttern , wählt der Optimierer aufgrund der Schätzungen für 1 Zeile einen Schleifenverknüpfungspunkt. Wie kann die Schätzung auf dieser Ebene verbessert werden, um zu vermeiden, dass der Join-Hinweis für übergeordnete Abfragen überschrieben wird oder auf einen SP zurückgegriffen wird?
Die Verwendung eines fest codierten Datums funktioniert hervorragend:
select distinct SessionId from [User].Session -- 2.9M (great)
where CreatedUtc > '04/08/2015' -- but hardcoded
Diese äquivalenten Abfragen sind mit der Ansicht kompatibel, aber alle schätzen 1 Zeile:
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)
Versuchen Sie einige Hinweise (aber N / A zum Anzeigen):
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);
Versuchen Sie es mit Parameter / Hints (aber N / A zum Anzeigen):
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);
Die Statistiken sind aktuell.
DBCC SHOW_STATISTICS('user.Session', 'IX_User_Session_CreatedUtc') with histogram;
Die letzten Zeilen des Histogramms (insgesamt 189 Zeilen) werden angezeigt:
quelle
>= DATEADD(DAY, -365, SYSDATETIME())
der Fehler darin besteht, dass die Schätzung auf basiert>= SYSDATETIME()
. Technisch gesehen basiert die Schätzung also darauf, wie viele Zeilen in der TabelleCreatedUtc
in Zukunft eine haben. Dies ist wahrscheinlich 0, aber SQL Server rundet 0 für geschätzte Zeilen immer auf 1 auf.Ersetzen Sie dateadd () durch dateiff (), um einen angemessenen ungefähren Wert (30% ish) zu erhalten.
Dies scheint ein Fehler zu sein, der MS Connect 630583 ähnelt .
Die Neukompilierung von Optionen macht keinen Unterschied.
quelle