SQL Server, bir sorgu planı için eksik dizin önerilerindeki anahtar sütunların sırasını nasıl belirler?
SQL Server, bir sorgu planı için eksik dizin önerilerindeki anahtar sütunların sırasını nasıl belirler?
Yanıtlar:
SQL Server, belirli bir sorgu planı için eksik bir dizin önerisi oluşturduğunda, olası anahtar sütunları 2 gruba ayırır. İlk set, bir EQUALITY yüklemesinin parçası olan önerilen tüm sütunları içerir. İkinci set, bir INEQUALITY yükleminin parçası olan önerilen tüm sütunları içerir.
Her bir kümede, sütunlar, tablo tanımına bağlı olarak, sütunların sıralı konumuna göre sıralanır.
(Bunu kanıtlamak için Stack Overflow veritabanına karşı bir repro betiği hazırladığı için Brent Ozar'a teşekkür ederiz!)
1. Aynı 3 tablo oluşturun , ancak sütunlarını farklı sıraya koyun. (Buradaki neden, eksik dizin önerisinde sütun sırasını etkilemediğini göstermek için çeşitli sütun adları ve veri türleri kullanmaktır.)
CREATE TABLE dbo.NumberLetterDate (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fINT INT, fNVARCHAR NVARCHAR(40), fDATE DATETIME, AboutMe NVARCHAR(MAX));
GO
CREATE TABLE dbo.LetterDateNumber (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fNVARCHAR NVARCHAR(40), fDATE DATETIME, fINT INT, AboutMe NVARCHAR(MAX));
GO
CREATE TABLE dbo.DateNumberLetter (ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
fDATE DATETIME, fINT INT, fNVARCHAR NVARCHAR(40), AboutMe NVARCHAR(MAX));
GO
2. Tabloları aynı verilerle doldurun. Gerçek dünya veri dağıtımıyla Kullanıcılar tablosundan 100.000 satır alın.
INSERT INTO dbo.NumberLetterDate(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
FROM dbo.Users WITH (NOLOCK)
ORDER BY Id;
GO
INSERT INTO dbo.LetterDateNumber(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
FROM dbo.Users WITH (NOLOCK)
ORDER BY Id;
GO
INSERT INTO dbo.DateNumberLetter(fINT, fNVARCHAR, fDATE, AboutMe)
SELECT TOP 100000 Age, DisplayName, LastAccessDate, AboutMe
FROM dbo.Users WITH (NOLOCK)
ORDER BY Id;
GO
3. Dizin gerektiren bir sorgu yazın. 3 eşitlik filtresiyle başlayın, her 3 alanda da kesin bir değere bakın. 3 sorgunun hepsinin aynı sırada aynı alanlara sahip olduğunu unutmayın:
SELECT ID
FROM dbo.NumberLetterDate
WHERE fINT = 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.LetterDateNumber
WHERE fINT = 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.DateNumberLetter
WHERE fINT = 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
GO
Her üç tablo da aynı veriye sahiptir ve sorgular aynıdır. Tek fark saha emridir - ve eksik endeks taleplerimizdeki de fark bu:
Uygulama planlarında, eksik indeks isteğindeki sütun sırası, tablodaki sütun sırası ile tam olarak eşleşiyor. Örneğin, dbo.NumberLetterDate'de sayı sütunu ilk sıradadır, bu nedenle eksik dizin isteğinde de ilk sırada bulunur:
Bunun gibi tek bir tablo için, dizin alanı sırası, seçiciliğe, veri türüne veya sorgudaki konuma bağlı görünmüyor. (Bunu daha karmaşık sorgular ve katılımlarla kanıtlamak için diğer insanlara bırakıyorum.)
4. Bir eşitsizlik filtresinde karıştırın. INT alanında, örneğin, filtre olarak <> 100 koyun:
SELECT ID
FROM dbo.NumberLetterDate
WHERE fINT <> 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.LetterDateNumber
WHERE fINT <> 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.DateNumberLetter
WHERE fINT <> 100
AND fNVARCHAR = 'Brent Ozar'
AND fDATE = '2018/01/01'
AND 1 = (SELECT 1);
GO
Yürütme planlarında eşitlik alanları önce gider, sonra eşitsizlik alanları - yani burada fINT, eksik olan 3 endeks talebinde en son ortaya çıkar çünkü bu bir eşitsizlik araştırmasıdır:
5. 3 eşitsizlik filtresi kullanın. Tüm alanlar için aynı aramayı kullanın (<>):
SELECT ID
FROM dbo.NumberLetterDate
WHERE fINT <> 100
AND fNVARCHAR <> 'Brent Ozar'
AND fDATE <> '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.LetterDateNumber
WHERE fINT <> 100
AND fNVARCHAR <> 'Brent Ozar'
AND fDATE <> '2018/01/01'
AND 1 = (SELECT 1);
SELECT ID
FROM dbo.DateNumberLetter
WHERE fINT <> 100
AND fNVARCHAR <> 'Brent Ozar'
AND fDATE <> '2018/01/01'
AND 1 = (SELECT 1);
GO
Eşitlik araması olmadığından, 3 alanın tümü de eksik dizin önerisinde aynı öncelik sırasına sahiptir ve şimdi tamamen alan sıralamasına göre sıralamaya döndük: