Bagaimana SQL Server menentukan urutan kolom kunci dalam rekomendasi indeks yang hilang untuk rencana kueri?
Bagaimana SQL Server menentukan urutan kolom kunci dalam rekomendasi indeks yang hilang untuk rencana kueri?
Jawaban:
Ketika SQL Server membuat rekomendasi indeks yang hilang untuk rencana kueri tertentu, itu memisahkan kolom kunci yang mungkin menjadi 2 kelompok. Set pertama berisi semua kolom yang direkomendasikan yang merupakan bagian dari predikat EQUALITY. Set kedua berisi semua kolom yang direkomendasikan yang merupakan bagian dari predikat INEQUALITY.
Dalam setiap set, kolom diurutkan berdasarkan posisi ordinal kolom, berdasarkan definisi tabel.
(Banyak terima kasih kepada Brent Ozar untuk membangun skrip repro terhadap database Stack Overflow untuk membuktikan ini!)
1. Buat 3 tabel identik , tetapi letakkan kolom mereka dalam urutan yang berbeda. (Alasannya di sini adalah untuk menggunakan berbagai nama kolom dan tipe data untuk menunjukkan bahwa itu tidak memengaruhi urutan kolom dalam rekomendasi indeks yang hilang.)
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. Isi tabel dengan data yang sama. Dapatkan 100.000 baris dari tabel Users dengan distribusi data dunia nyata.
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. Tulis kueri yang membutuhkan indeks. Mulai dengan 3 filter kesetaraan, pemfilteran untuk nilai yang tepat di ketiga bidang. Perhatikan bahwa semua 3 kueri memiliki bidang yang sama dalam urutan yang sama:
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
Ketiga tabel memiliki data yang persis sama, dan kueri identik. Satu-satunya perbedaan adalah urutan bidang - dan itulah perbedaan dalam permintaan indeks yang hilang juga:
Dalam rencana eksekusi, urutan kolom dalam permintaan indeks yang hilang sama persis dengan urutan kolom dalam tabel. Misalnya, di dbo.NumberLetterDate, kolom angka adalah yang pertama, jadi itu juga yang pertama dalam permintaan indeks yang hilang, juga:
Untuk operasi satu-tabel seperti ini, urutan bidang indeks tampaknya tidak bergantung pada selektivitas, tipe data, atau posisi dalam kueri. (Saya serahkan kepada orang lain untuk membuktikan ini dengan pertanyaan & bergabung yang lebih kompleks.)
4. Campurkan filter ketimpangan. Pada bidang INT, misalnya, masukkan <> 100 sebagai filter:
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
Dalam rencana eksekusi, bidang persamaan pertama-tama, kemudian bidang ketidaksetaraan - jadi di sini, fINT muncul terakhir di ketiga permintaan indeks yang hilang karena ini merupakan pencarian ketidaksetaraan:
5. Gunakan 3 filter ketimpangan. Gunakan pencarian yang sama untuk semua bidang (<>):
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
Karena tidak ada pencarian kesetaraan, ketiga bidang memiliki urutan prioritas yang sama dalam rekomendasi indeks yang hilang, dan sekarang kami kembali menyortir murni berdasarkan urutan bidang: