これまでのキャストの可算性の背後にあるメカニズムは、動的シークと呼ばれます。
SQL Serverは内部関数GetRangeThroughConvert
を呼び出して、範囲の開始と終了を取得します。
多少驚くべきことに、これはリテラル値と同じ範囲ではありません。
1ページあたり1行、1日あたり1440行のテーブルを作成する
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
その後、実行中
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';
最初のクエリには1443
読み取りがあり、2番目のクエリには1 2883
日全体を読み取り、残りの述部に対してそれを破棄しています。
プランは、シーク述語が
Seek Keys[1]: Start: DateTimeCol > Scalar Operator([Expr1006]),
End: DateTimeCol < Scalar Operator([Expr1007])
その>= '20130101' ... < '20130102'
ため、読み取りの代わりに> '20121231' ... < '20130102'
すべての2012-12-31
行を破棄します。
これに依存する別の欠点は、カーディナリティの推定が従来の範囲クエリほど正確ではない可能性があることです。これは、SQL Fiddleの修正バージョンで確認できます。
テーブル内の100行すべてが述部と一致するようになりました(同じ日にすべての日付時刻が1分離れている)。
2番目の(範囲)クエリは、100が一致することを正しく推定し、クラスター化インデックススキャンを使用します。CAST( AS DATE)
クエリが間違って一列のみが一致することを推定し、キーを検索して計画を作成します。
統計は完全に無視されません。テーブル内のすべての行が同じdatetime
で、述部(20130101 00:00:00
または20130101 01:00:00
)に一致する場合、プランには、推定31.6228行のクラスター化インデックススキャンが表示されます。
100 ^ 0.75 = 31.6228
したがって、その場合、推定値はここの式から導出されます。
テーブル内のすべての行が同じでdatetime
あり、述語と一致しない場合(例:)20130102 01:00:00
、推定行カウント1およびルックアップ付きプランにフォールバックします。
テーブルに複数のDISTINCT
値がある場合、推定される行は、クエリが正確に探していた場合と同じように見えます20130101 00:00:00
。
統計ヒストグラムにステップがある2013-01-01 00:00:00.000
場合、推定値はEQ_ROWS
(つまり、その日付の他の時間を考慮に入れていない)に基づきます。それ以外の場合、ステップがない場合はAVG_RANGE_ROWS
、周囲のステップのを使用するかのように見えます。
datetime
多くのシステムでは、約3ミリ秒の精度を持っているが、非常に少数の実際の重複した値となり、この数は1になります。