Механізм, що стоїть на сьогоднішній день за стійкістю лиття, називається динамічним пошуком .
SQL Server викликає внутрішню функцію, GetRangeThroughConvert
щоб отримати початок і кінець діапазону.
Дещо дивно, що це не той діапазон, як ваші буквальні цінності.
Створення таблиці з рядком на сторінці та 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
читає, а другий, 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 хвилину, всі в один і той же день).
Другий запит (діапазон) правильно оцінює, що 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.