Der Mechanismus hinter der Sargabilität des bisherigen Castings heißt dynamisches Suchen .
SQL Server ruft eine interne Funktion GetRangeThroughConvert
auf, um den Anfang und das Ende des Bereichs abzurufen.
Es ist etwas überraschend, dass dies nicht der gleiche Bereich ist wie Ihre Literalwerte.
Erstellen einer Tabelle mit einer Zeile pro Seite und 1440 Zeilen pro Tag
CREATE TABLE T
(
DateTimeCol DATETIME PRIMARY KEY,
Filler CHAR(8000) DEFAULT 'X'
);
WITH Nums(Num)
AS (SELECT number
FROM spt_values
WHERE type = 'P'
AND number BETWEEN 1 AND 1440),
Dates(Date)
AS (SELECT {d '2012-12-30'} UNION ALL
SELECT {d '2012-12-31'} UNION ALL
SELECT {d '2013-01-01'} UNION ALL
SELECT {d '2013-01-02'} UNION ALL
SELECT {d '2013-01-03'})
INSERT INTO T
(DateTimeCol)
SELECT DISTINCT DATEADD(MINUTE, Num, Date)
FROM Nums,
Dates
Dann rennen
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT *
FROM T
WHERE DateTimeCol >= '20130101'
AND DateTimeCol < '20130102'
SELECT *
FROM T
WHERE CAST(DateTimeCol AS DATE) = '20130101';
Die erste Abfrage 1443
lautet "read" und die zweite " 2883
read", sodass ein ganzer zusätzlicher Tag gelesen und dann gegen ein verbleibendes Prädikat verworfen wird.
Der Plan zeigt, dass das Suchprädikat ist
Seek Keys[1]: Start: DateTimeCol > Scalar Operator([Expr1006]),
End: DateTimeCol < Scalar Operator([Expr1007])
Also anstatt >= '20130101' ... < '20130102'
es zu lesen, werden > '20121231' ... < '20130102'
dann alle 2012-12-31
Zeilen verworfen .
Ein weiterer Nachteil der Verwendung ist, dass die Kardinalitätsschätzungen möglicherweise nicht so genau sind wie bei der herkömmlichen Bereichsabfrage. Dies kann in einer geänderten Version Ihrer SQL-Geige gesehen werden .
Alle 100 Zeilen in der Tabelle stimmen jetzt mit dem Prädikat überein (mit einem Abstand von 1 Minute am selben Tag).
Die zweite Abfrage (Bereich) schätzt korrekt, dass 100 übereinstimmt, und verwendet einen Clustered-Index-Scan. Die CAST( AS DATE)
Abfrage schätzt fälschlicherweise, dass nur eine Zeile übereinstimmt, und erstellt einen Plan mit Schlüsselsuchen.
Die Statistiken werden nicht vollständig ignoriert. Wenn alle Zeilen in der Tabelle identisch sind datetime
und mit dem Prädikat (z. B. 20130101 00:00:00
oder 20130101 01:00:00
) übereinstimmen, zeigt der Plan einen Clustered-Index-Scan mit geschätzten 31.6228 Zeilen an.
100 ^ 0.75 = 31.6228
In diesem Fall wird die Schätzung also aus der hier angegebenen Formel abgeleitet .
Wenn alle Zeilen in der Tabelle gleich sind datetime
und sie nicht mit dem Prädikat übereinstimmen (z. B. 20130102 01:00:00
), wird auf die geschätzte Zeilenanzahl von 1 und den Plan mit Nachschlägen zurückgegriffen.
In den Fällen, in denen die Tabelle mehr als einen DISTINCT
Wert enthält, scheinen die geschätzten Zeilen so zu sein, als ob die Abfrage genau danach gesucht hätte 20130101 00:00:00
.
Wenn das Statistik-Histogramm zu einem bestimmten 2013-01-01 00:00:00.000
Zeitpunkt einen Sprung aufweist , basiert die Schätzung auf dem EQ_ROWS
(dh, andere Zeitpunkte an diesem Datum werden nicht berücksichtigt). Andernfalls sieht es so aus, als würde die AVG_RANGE_ROWS
von den umliegenden Stufen verwendet, wenn es keine Stufe gibt .
Da datetime
es in vielen Systemen eine Genauigkeit von ca. 3 ms gibt, gibt es nur sehr wenige doppelte Werte, und diese Zahl ist 1.