Saya memiliki kolom yang tetap dihitung pada tabel yang hanya terdiri kolom gabungan, misalnya
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
);
Dalam hal Comp
ini tidak unik, dan D adalah valid dari tanggal setiap kombinasi A, B, C
, oleh karena itu saya menggunakan kueri berikut untuk mendapatkan tanggal akhir untuk masing-masing A, B, C
(pada dasarnya tanggal mulai berikutnya untuk nilai Comp yang sama):
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;
Saya kemudian menambahkan indeks ke kolom yang dihitung untuk membantu dalam permintaan ini (dan juga yang lain):
CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;
Namun rencana kueri mengejutkan saya. Saya akan berpikir bahwa karena saya memiliki klausa di mana menyatakan itu D IS NOT NULL
dan saya menyortir Comp
, dan tidak merujuk kolom di luar indeks bahwa indeks pada kolom dihitung dapat digunakan untuk memindai t1 dan t2, tetapi saya melihat indeks berkerumun memindai.
Jadi saya memaksakan penggunaan indeks ini untuk melihat apakah itu menghasilkan rencana yang lebih baik:
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;
Yang memberi rencana ini
Ini menunjukkan bahwa pencarian kunci sedang digunakan, rinciannya adalah:
Sekarang, menurut dokumentasi SQL-Server:
Anda dapat membuat indeks pada kolom yang dihitung yang didefinisikan dengan ekspresi deterministik, tetapi tidak tepat, jika kolom ditandai PERSISTED dalam pernyataan CREATE TABLE atau ALTER TABLE. Ini berarti bahwa Database Engine menyimpan nilai yang dihitung dalam tabel, dan memutakhirkannya ketika kolom lain yang bergantung pada kolom yang dihitung diperbarui. Mesin Database menggunakan nilai-nilai tetap ini ketika itu membuat indeks pada kolom, dan ketika indeks direferensikan dalam kueri. Opsi ini memungkinkan Anda untuk membuat indeks pada kolom yang dihitung ketika Database Engine tidak dapat membuktikan dengan akurat apakah suatu fungsi yang mengembalikan ekspresi kolom yang dihitung, khususnya fungsi CLR yang dibuat dalam .NET Framework, keduanya deterministik dan tepat.
Jadi jika, seperti dokumen mengatakan "Mesin Basis Data menyimpan nilai yang dihitung dalam tabel" , dan nilainya juga disimpan dalam indeks saya, mengapa Pencarian Kunci diperlukan untuk mendapatkan A, B dan C ketika mereka tidak dirujuk dalam pertanyaannya sama sekali? Saya berasumsi mereka sedang digunakan untuk menghitung Comp, tetapi mengapa? Juga, mengapa kueri dapat menggunakan indeks aktif t2
, tetapi tidak aktif t1
?
NB Saya telah menandai SQL Server 2008 karena ini adalah versi yang menjadi masalah utama saya, tetapi saya juga mendapatkan perilaku yang sama pada tahun 2012.