У меня есть постоянный вычисляемый столбец в таблице, который просто состоит из сцепленных столбцов, например
CREATE TABLE dbo.T
(
ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY,
A VARCHAR(20) NOT NULL,
B VARCHAR(20) NOT NULL,
C VARCHAR(20) NOT NULL,
D DATE NULL,
E VARCHAR(20) NULL,
Comp AS A + '-' + B + '-' + C PERSISTED NOT NULL
);
Это Comp
не уникально, и D является действительной датой каждой комбинации A, B, C
, поэтому я использую следующий запрос, чтобы получить конечную дату для каждой A, B, C
(в основном, следующую начальную дату для того же значения Comp):
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1
WHERE t1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY t1.Comp;
Затем я добавил индекс в вычисляемый столбец, чтобы помочь в этом запросе (а также других):
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
Однако план запроса меня удивил. Я бы подумал, что, поскольку у меня есть предложение where, в котором указано, что D IS NOT NULL
я сортирую Comp
, а не ссылаюсь ни на один столбец за пределами индекса, индекс для вычисляемого столбца можно использовать для сканирования t1 и t2, но я увидел кластеризованный индекс сканирования.
Поэтому я заставил использовать этот индекс, чтобы увидеть, дает ли он лучший план:
SELECT t1.ID,
t1.Comp,
t1.D,
D2 = ( SELECT TOP 1 t2.D
FROM dbo.T t2
WHERE t2.Comp = t1.Comp
AND t2.D > t1.D
ORDER BY t2.D
)
FROM dbo.T t1 WITH (INDEX (IX_T_Comp_D))
WHERE t1.D IS NOT NULL
ORDER BY t1.Comp;
Который дал этот план
Это показывает, что используется поиск ключа, подробности которого:
Теперь согласно документации SQL-сервера:
Вы можете создать индекс для вычисляемого столбца, который определен с помощью детерминированного, но неточного выражения, если столбец помечен как PERSISTED в операторе CREATE TABLE или ALTER TABLE. Это означает, что компонент Database Engine сохраняет вычисленные значения в таблице и обновляет их при обновлении любых других столбцов, от которых зависит вычисляемый столбец. Компонент Database Engine использует эти постоянные значения при создании индекса для столбца и при ссылке на индекс в запросе. Этот параметр позволяет создать индекс для вычисляемого столбца, когда компонент Database Engine не может с точностью доказать, является ли функция, которая возвращает выражения вычисляемого столбца, в частности, функция CLR, созданная в .NET Framework, детерминистической и точной.
Поэтому, если, как говорят документы, « компонент Database Engine хранит вычисленные значения в таблице» , а значение также сохраняется в моем индексе, почему для поиска A, B и C требуется поиск ключей, если на них нет ссылок в запрос вообще? Я предполагаю, что они используются для вычисления Comp, но почему? Кроме того, почему запрос может использовать индекс включен t2
, но не включен t1
?
NB Я пометил SQL Server 2008, потому что это версия, на которой моя основная проблема, но я также получаю такое же поведение в 2012 году.