Mam utrwaloną kolumnę obliczeniową na stole, która jest po prostu złożona z połączonych kolumn, np
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
);
W tym Comp
nie jest unikalny, a D jest prawidłowy od daty każdej kombinacji A, B, C
, dlatego używam następującego zapytania, aby uzyskać datę końcową dla każdej A, B, C
(w zasadzie następnej daty początkowej dla tej samej wartości 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;
Następnie dodałem indeks do kolumny obliczanej, aby pomóc w tym zapytaniu (i innych):
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
Plan zapytania mnie jednak zaskoczył. Pomyślałbym, że skoro mam klauzulę where stwierdzającą to D IS NOT NULL
i sortuję według Comp
, i nie odnoszę się do żadnej kolumny poza indeksem, to że indeks w kolumnie obliczeniowej może być użyty do skanowania t1 i t2, ale widziałem indeks klastrowany skandować.
Zmusiłem więc użycie tego indeksu, aby sprawdzić, czy przyniósł lepszy plan:
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;
Co dało ten plan
To pokazuje, że używane jest wyszukiwanie klucza, którego szczegółami są:
Teraz, zgodnie z dokumentacją SQL-Server:
Można utworzyć indeks w kolumnie obliczanej, która jest zdefiniowana za pomocą deterministycznego, ale nieprecyzyjnego wyrażenia, jeśli kolumna jest oznaczona jako PERSISTED w instrukcji CREATE TABLE lub ALTER TABLE. Oznacza to, że Aparat baz danych przechowuje obliczone wartości w tabeli i aktualizuje je, gdy są aktualizowane inne kolumny, od których zależy obliczona kolumna. Aparat baz danych korzysta z tych utrwalonych wartości podczas tworzenia indeksu w kolumnie i do odwołania do indeksu w zapytaniu. Ta opcja umożliwia utworzenie indeksu w kolumnie obliczeniowej, gdy aparat bazy danych nie może dokładnie udowodnić, czy funkcja zwracająca wyrażenia w kolumnie obliczeniowej, w szczególności funkcja CLR utworzona w .NET Framework, jest zarówno deterministyczna, jak i precyzyjna.
Jeśli więc, jak mówią doktorzy: „ Aparat baz danych przechowuje obliczone wartości w tabeli” , a wartość jest również przechowywana w moim indeksie, dlaczego wymagane jest wyszukiwanie klucza, aby uzyskać A, B i C, gdy nie ma w nich odwołania zapytanie w ogóle? Zakładam, że są one używane do obliczania Comp, ale dlaczego? Ponadto, dlaczego zapytanie może korzystać z indeksu na t2
, ale nie na t1
?
Uwaga: otagowałem SQL Server 2008, ponieważ jest to wersja, na której jest mój główny problem, ale otrzymuję to samo zachowanie w 2012 roku.