Verilerinizi çarpıttığınızı, optimize ediciyi ne yapmaya zorlamak için sorgulama ipuçlarını kullanmak istemediğinizi ve tüm olası giriş değerleri için iyi bir performans elde etmeniz gerektiğini varsayacağım @Id
. Aşağıdaki indeks çiftlerini (veya eşdeğerlerini) oluşturmak istiyorsanız, olası herhangi bir giriş değeri için yalnızca birkaç avuç mantıksal okuma gerektiren bir sorgu planı alabilirsiniz:
CREATE INDEX GetMinSomeTimestamp ON dbo.MyTable (Id, SomeTimestamp) WHERE SomeBit = 1;
CREATE INDEX GetMaxSomeInt ON dbo.MyTable (Id, SomeInt) WHERE SomeBit = 1;
Test verilerim aşağıdadır. Tabloya 13 M satır koydum ve bunların yarısının sütun '3A35EA17-CE7E-4637-8319-4C517B6E48CA'
için bir değeri vardı Id
.
DROP TABLE IF EXISTS dbo.MyTable;
CREATE TABLE dbo.MyTable (
Id uniqueidentifier,
SomeTimestamp DATETIME2,
SomeInt INT,
SomeBit BIT,
FILLER VARCHAR(100)
);
INSERT INTO dbo.MyTable WITH (TABLOCK)
SELECT NEWID(), CURRENT_TIMESTAMP, 0, 1, REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
INSERT INTO dbo.MyTable WITH (TABLOCK)
SELECT '3A35EA17-CE7E-4637-8319-4C517B6E48CA', CURRENT_TIMESTAMP, 0, 1, REPLICATE('Z', 100)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Bu sorgu ilk başta biraz garip görünebilir:
DECLARE @Id UNIQUEIDENTIFIER = '3A35EA17-CE7E-4637-8319-4C517B6E48CA'
SELECT
@Id,
st.SomeTimestamp,
si.SomeInt
FROM (
SELECT TOP (1) SomeInt, Id
FROM dbo.MyTable
WHERE Id = @Id
AND SomeBit = 1
ORDER BY SomeInt DESC
) si
CROSS JOIN (
SELECT TOP (1) SomeTimestamp, Id
FROM dbo.MyTable
WHERE Id = @Id
AND SomeBit = 1
ORDER BY SomeTimestamp ASC
) st;
Birkaç mantıksal okuma ile min veya maks değerini bulmak için indekslerin sıralanmasından yararlanmak için tasarlanmıştır. CROSS JOIN
İçin herhangi bir eşleme satır yokken doğru sonuçlar elde etmek için orada @Id
değer. Tablodaki en popüler değere filtre uygulasam bile (6.5 milyon satır eşleşiyor) Yalnızca 8 mantıksal okuma alıyorum:
'MyTable' tablosu. Tarama sayısı 2, mantıksal okuma 8
İşte sorgu planı:
Her iki dizin de 0 veya 1 satır bulmaya çalışır. Son derece verimli, ancak iki dizin oluşturmak, senaryonuz için aşırı yüklenebilir. Bunun yerine aşağıdaki dizini düşünebilirsiniz:
CREATE INDEX CoveringIndex ON dbo.MyTable (Id) INCLUDE (SomeTimestamp, SomeInt) WHERE SomeBit = 1;
Şimdi orijinal sorgu için sorgu planı (isteğe bağlı bir MAXDOP 1
ipucu ile) biraz farklı görünüyor:
Anahtar aramaları artık gerekli değildir. Tüm girişler için iyi çalışması gereken daha iyi bir erişim yolu ile, yoğunluk vektöründen dolayı yanlış sorgu planını seçen optimizer konusunda endişelenmenize gerek yoktur. Ancak, bu sorgu ve dizin popüler bir @Id
değere bakarsanız, diğeri kadar verimli olmayacaktır .
'MyTable' tablosu. Tarama sayısı 1, mantıksal okuma 33757