Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

La query viene eseguita lentamente con l'espressione della data, ma veloce con la stringa letterale

Questo potrebbe funzionare meglio:

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

A meno che tu non stia utilizzando il flag di traccia 4199, è presente un bug che influisce sulle stime di cardinalità. Nel momento in cui scrivo

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

Resi

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

Il bug è che il predicato nella domanda utilizza la prima data anziché la seconda quando deriva le stime di cardinalità. Quindi per la seguente configurazione.

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)

Richiesta 1

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

Stima che il numero di righe corrispondenti sarà 100.000. Questo è il numero che corrisponde alla data '1786-06-01' .

Ma entrambe le seguenti query

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)

Dai questo piano

A causa delle stime molto più accurate della cardinalità, il piano ora esegue solo una ricerca di un singolo indice anziché una scansione completa.