Bu genel olarak çözülmesi zor bir sorundur, ancak optimize edicinin bir plan seçmesine yardımcı olmak için yapabileceğimiz birkaç şey vardır. Bu komut dosyası, gösterilecek 10.000 sıralı bilinen bir sözde rastgele dağılım tablosu içeren bir tablo oluşturur:
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
İlk soru bu tablonun nasıl endeksleneceğidir. Seçeneklerden biri DATETIME
sütunlara iki dizin sağlamaktır , böylece optimize edici en azından StartDate
veya üzerinde arama yapmayı seçebilir EndDate
.
CREATE INDEX nc1 ON dbo.SomeDateTable (StartDate, EndDate)
CREATE INDEX nc2 ON dbo.SomeDateTable (EndDate, StartDate)
Doğal olarak, hem de eşitsizlikler StartDate
ve EndDate
her endekste sadece bir sütun, bir destek olabilir ortalama örnek sorguda aramak, ancak bu yapabileceğimiz en iyisi bu. Her dizindeki ikinci sütunu INCLUDE
bir anahtar yerine bir anahtar haline getirebiliriz, ancak önde gelen sütunda eşitlik araması ve ikinci sütunda eşitsizlik araması gerçekleştirebilecek başka sorgularımız olabilir. Ayrıca, bu şekilde daha iyi istatistikler elde edebiliriz. Neyse ...
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
Bu sorgu değişkenleri kullanır, bu nedenle genel olarak optimizatör seçicilik ve dağılımı tahmin eder, bu da 81 satırlık tahmini bir kardinalite tahmini ile sonuçlanır . Aslında, sorgu daha karmaşık bir örnekte önemli olabilecek bir tutarsızlık olan 2076 satır üretir.
SQL Server 2008 SP1 CU5 veya sonraki sürümlerinde (veya R2 RTM CU1) Parametre Gömme Optimizasyonu basitçe ekleyerek, daha iyi tahminler almak için OPTION (RECOMPILE)
için SELECT
yukarıdaki sorguda. Bu, toplu işlem yürütülmeden hemen önce bir derlemeye neden olarak SQL Server'ın gerçek parametre değerlerini 'görmesini' ve bunlar için optimize etmesini sağlar. Bu değişiklikle, tahmin 468 satıra yükselir (bunu görmek için çalışma zamanı planını kontrol etmeniz gerekir). Bu tahmin 81 satırdan daha iyidir, ancak yine de hepsi bu kadar yakın değildir. İzleme bayrağı 2301 tarafından etkinleştirilen modelleme uzantıları bazı durumlarda yardımcı olabilir, ancak bu sorguda yardımcı olmaz.
Sorun, iki aralık araması tarafından nitelenen satırların çakıştığıdır. Optimize edicinin maliyetleme ve kardinalite tahmin bileşeninde yapılan basitleştirici varsayımlardan biri, tahminlerin bağımsız olmasıdır (her ikisinin de% 50'lik bir seçiciliği varsa, her ikisini de uygulamanın sonucunun% 50'nin% 50'sini = satırların% 25'ini nitelediği varsayılır. ). Bu tür bir korelasyonun bir sorun olduğu durumlarda, genellikle çok sütunlu ve / veya filtrelenmiş istatistiklerle çalışabiliriz. Başlangıç ve bitiş noktaları bilinmeyen iki aralık ile bu pratik değildir. Bu, bazen daha iyi bir tahmin oluşturmak için sorguyu yeniden yazmak için başvurmak zorunda olduğumuz yerdir:
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)
Bu form, 2110 satırlık bir çalışma zamanı tahmini üretir (gerçek 2076'ya göre). TF 2301'iniz açık değilse, bu durumda daha gelişmiş modelleme teknikleri hile yoluyla görür ve daha önce olduğu gibi aynı tahmini üretir: 468 satır.
Bir gün SQL Server, aralıklarla yerel destek alabilir. Bu, iyi bir istatistiksel destekle geliyorsa, geliştiriciler bu gibi sorgu planlarını biraz daha az korkutabilir.