Ini adalah masalah yang sulit untuk dipecahkan secara umum, tetapi ada beberapa hal yang dapat kita lakukan untuk membantu pengoptimal memilih rencana. Script ini membuat tabel dengan 10.000 baris dengan distribusi baris pseudo-acak yang dikenal untuk menggambarkan:
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
Pertanyaan pertama adalah bagaimana cara mengindeks tabel ini. Salah satu opsi adalah menyediakan dua indeks pada DATETIME
kolom, sehingga pengoptimal setidaknya dapat memilih apakah akan mencari StartDate
atau EndDate
.
CREATE INDEX nc1 ON dbo.SomeDateTable (StartDate, EndDate)
CREATE INDEX nc2 ON dbo.SomeDateTable (EndDate, StartDate)
Tentu saja, ketidaksetaraan pada keduanya StartDate
dan EndDate
berarti bahwa hanya satu kolom di setiap indeks dapat mendukung pencarian dalam contoh query, tetapi ini adalah tentang yang terbaik yang bisa kita lakukan. Kami mungkin mempertimbangkan menjadikan kolom kedua di setiap indeks sebagai INCLUDE
bukan kunci, tetapi kami mungkin memiliki kueri lain yang dapat melakukan pencarian kesetaraan pada kolom utama dan pencarian ketidaksetaraan pada kolom kedua. Juga, kita bisa mendapatkan statistik yang lebih baik dengan cara ini. Bagaimanapun...
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
Kueri ini menggunakan variabel, jadi secara umum pengoptimal akan menebak selektivitas dan distribusi, sehingga menghasilkan perkiraan kardinalitas 81 baris . Bahkan, kueri menghasilkan 2076 baris, perbedaan yang mungkin penting dalam contoh yang lebih kompleks.
Pada SQL Server 2008 SP1 CU5 atau lambat (atau R2 RTM CU1) kita dapat mengambil keuntungan dari Parameter Embedding Optimization untuk mendapatkan perkiraan yang lebih baik, hanya dengan menambahkan OPTION (RECOMPILE)
ke SELECT
pertanyaan di atas. Ini menyebabkan kompilasi sesaat sebelum batch dijalankan, memungkinkan SQL Server untuk 'melihat' nilai parameter nyata dan mengoptimalkannya. Dengan perubahan ini, perkiraan meningkat menjadi 468 baris (walaupun Anda perlu memeriksa paket runtime untuk melihatnya). Perkiraan ini lebih baik dari 81 baris, tetapi masih belum terlalu dekat. Ekstensi pemodelan yang diaktifkan oleh tanda jejak 2301 dapat membantu dalam beberapa kasus, tetapi tidak dengan kueri ini.
Masalahnya adalah di mana baris yang dikualifikasikan oleh dua rentang pencarian tumpang tindih. Salah satu asumsi penyederhanaan yang dibuat dalam komponen estimasi biaya dan kardinalitas optimizer adalah bahwa predikat independen (jadi jika keduanya memiliki selektivitas 50%, hasil penerapan keduanya diasumsikan memenuhi syarat 50% dari 50% = 25% dari baris ). Di mana korelasi semacam ini merupakan masalah, kita sering dapat mengatasinya dengan statistik multi-kolom dan / atau difilter. Dengan dua rentang dengan titik awal dan akhir yang tidak diketahui, ini menjadi tidak praktis. Di sinilah kadang-kadang kita harus menggunakan penulisan ulang kueri ke formulir yang menghasilkan perkiraan yang lebih baik:
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)
Bentuk ini terjadi untuk menghasilkan perkiraan runtime 2110 baris (dibandingkan 2076 aktual). Kecuali Anda memiliki TF 2301 pada, dalam hal ini teknik pemodelan yang lebih maju melihat melalui trik dan menghasilkan perkiraan yang persis sama seperti sebelumnya: 468 baris.
Suatu hari SQL Server mungkin mendapatkan dukungan asli untuk interval. Jika itu datang dengan dukungan statistik yang baik, pengembang mungkin takut rencana tuning kueri seperti ini sedikit kurang.