Це важко вирішити проблему загалом, але є кілька речей, які ми можемо зробити, щоб допомогти оптимізатору вибрати план. Цей сценарій створює таблицю з 10000 рядків з відомим псевдовипадковим розподілом рядків для ілюстрації:
CREATE TABLE dbo.SomeDateTable
(
Id INTEGER IDENTITY(1, 1) PRIMARY KEY NOT NULL,
StartDate DATETIME NOT NULL,
EndDate DATETIME NOT NULL
);
GO
SET STATISTICS XML OFF
SET NOCOUNT ON;
DECLARE
@i INTEGER = 1,
@s FLOAT = RAND(20120104),
@e FLOAT = RAND();
WHILE @i <= 10000
BEGIN
INSERT dbo.SomeDateTable
(
StartDate,
EndDate
)
VALUES
(
DATEADD(DAY, @s * 365, {d '2009-01-01'}),
DATEADD(DAY, @s * 365 + @e * 14, {d '2009-01-01'})
)
SELECT
@s = RAND(),
@e = RAND(),
@i += 1
END
Перше питання - як індексувати цю таблицю. Одним з варіантів є створення двох індексів про DATETIME
шпальтах, тому оптимізатор може вибрати , по крайней мере , слід шукати на StartDate
або EndDate
.
CREATE INDEX nc1 ON dbo.SomeDateTable (StartDate, EndDate)
CREATE INDEX nc2 ON dbo.SomeDateTable (EndDate, StartDate)
Звичайно, нерівності обох StartDate
і EndDate
означають, що лише один стовпець у кожному індексі може підтримувати пошук у прикладі запиту, але це приблизно найкраще, що ми можемо зробити. Ми можемо розглянути можливість створення другого стовпця в кожному індексі INCLUDE
скоріше, ніж ключового, але у нас можуть бути інші запити, які можуть виконувати пошук рівності на провідному стовпчику та пошук нерівності у другому стовпчику. Також ми можемо отримати кращу статистику таким чином. Все одно ...
DECLARE
@StartDateBegin DATETIME = {d '2009-08-01'},
@StartDateEnd DATETIME = {d '2009-10-15'},
@EndDateBegin DATETIME = {d '2009-08-05'},
@EndDateEnd DATETIME = {d '2009-10-22'}
SELECT
COUNT_BIG(*)
FROM dbo.SomeDateTable AS sdt
WHERE
sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
AND sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd
Цей запит використовує змінні, тому в цілому оптимізатор вгадає про вибірковість та розподіл, в результаті чого здогадається оцінку кардинальності у 81 рядок . Насправді, запит видає 2076 рядків, розбіжність, яка може бути важливою у більш складному прикладі.
У SQL Server 2008 з пакетом оновлень 1 або пізнішої версії CU5 (або R2 RTM CU1) можна скористатися параметром Вбудовування оптимізації , щоб отримати більш точні оцінки, просто додавши OPTION (RECOMPILE)
до SELECT
запиту вище. Це спричиняє компіляцію перед початком виконання пакету, що дозволяє SQL Server "бачити" реальні значення параметрів та оптимізувати їх. З цією зміною оцінка покращується до 468 рядків (хоча для цього потрібно перевірити план виконання). Ця оцінка краща за 81 рядок, але все ще не все так близько. Розширення моделювання, включені прапором 2301 сліду, можуть допомогти в деяких випадках, але не в цьому запиті.
Проблема полягає в тому, що рядки, кваліфіковані за двома діапазонами пошуку, перетинаються. Одне із спрощених припущень, зроблених у складі оцінки вартості та кардинальності оптимізатора, полягає в тому, що предикати є незалежними (тому якщо обидва мають вибірковість 50%, результат застосування обох передбачається кваліфікувати 50% 50% = 25% рядків ). Там, де подібне співвідношення є проблемою, ми часто можемо обходити її за допомогою статистичних даних про багато стовпців та / або відфільтрованих даних. З двома діапазонами з невідомими початковими та кінцевими точками це стає недоцільним. Саме тут нам іноді доводиться вдаватися до переписування запиту до форми, яка, можливо, дає кращу оцінку:
SELECT COUNT(*) FROM
(
SELECT
sdt.Id
FROM dbo.SomeDateTable AS sdt
WHERE
sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
INTERSECT
SELECT
sdt.Id
FROM dbo.SomeDateTable AS sdt
WHERE
sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd
) AS intersected (id)
OPTION (RECOMPILE)
За допомогою цієї форми можна отримати оцінку часу виконання 2110 рядків (проти 2076 фактичних). Якщо у вас немає TF 2301, в цьому випадку більш досконалі методи моделювання бачать трюк і дають точно таку ж оцінку, як і раніше: 468 рядків.
Одного дня SQL Server може отримати вбудовану підтримку інтервалів. Якщо це приходить з гарною статистичною підтримкою, розробники можуть трохи боятися налаштування планів запитів.