Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Abfrage läuft langsam mit Datumsausdruck, aber schnell mit String-Literal

Das könnte besser funktionieren:

Where FK.DT = cast(getdate() + 1 - datepart(day, getdate()) as date)

Sofern Sie nicht mit aktiviertem Trace-Flag 4199 arbeiten, gibt es ein Fehler das wirkt sich auf die Kardinalitätsschätzungen aus. Zum Zeitpunkt des Schreibens

SELECT DATEADD(m, DATEDIFF(m, getdate(), 0), 0), 
       DATEADD(m, DATEDIFF(m, 0, getdate()), 0)

Rückgabe

+-------------------------+-------------------------+
| 1786-06-01 00:00:00.000 | 2013-08-01 00:00:00.000 |
+-------------------------+-------------------------+

Der Fehler besteht darin, dass das Prädikat in der Frage beim Ableiten der Kardinalitätsschätzungen das erste Datum und nicht das zweite verwendet. Also für das folgende Setup.

CREATE TABLE FK
(
ID INT IDENTITY PRIMARY KEY,
DT DATE,
Filler CHAR(1000) NULL,
UNIQUE (DT,ID)
)

INSERT INTO FK (DT)
SELECT TOP (1000000) DATEADD(m, DATEDIFF(m, getdate(), 0), 0)
FROM master..spt_values o1, master..spt_values o2
UNION ALL
SELECT               DATEADD(m, DATEDIFF(m, 0, getdate()), 0)

Abfrage 1

SELECT COUNT(Filler)
FROM FK
WHERE FK.DT = CAST(DATEADD(m, DATEDIFF(m, 0, getdate()), 0) AS DATE)  

Die Anzahl der übereinstimmenden Zeilen wird auf 100.000 geschätzt. Dies ist die Zahl, die dem Datum '1786-06-01' entspricht .

Aber die beiden folgenden Abfragen

SELECT COUNT(Filler)
FROM FK
WHERE FK.DT = CAST(GETDATE() + 1 - DATEPART(DAY, GETDATE()) AS DATE)

SELECT COUNT(Filler)
FROM FK
WHERE FK.DT = CAST(DATEADD(m, DATEDIFF(m, 0, getdate()), 0) AS DATE)  
OPTION (QUERYTRACEON 4199)

Geben Sie diesen Plan

Aufgrund der viel genaueren Kardinalitätsschätzungen führt der Plan jetzt nur noch eine einzelne Indexsuche statt eines vollständigen Scans durch.