Missing Non Clustered Index sudah menjadi bagian dari Clustered Index

9

Saya men-debug permintaan yang berjalan lambat dan dalam rencana pelaksanaan indeks yang tidak dikelompokkan disarankan, dengan Dampak 51.6648. Namun, indeks yang tidak berkerumun hanya mencakup kolom yang sudah ada di Indeks Gabungan Kunci Utama (PK).

Mungkinkah ini karena urutan kolom dalam indeks? yaitu jika kolom dalam indeks berkerumun tidak dalam urutan dari yang paling selektif ke yang paling tidak maka adakah potensi untuk indeks yang tidak berkerumun untuk meningkatkan kinerja?

Selain itu indeks non-cluster hanya berisi dua dari tiga kolom PK dengan yang ketiga ditambahkan sebagai kolom yang disertakan. Apakah includealasan lain mengapa penggunaan indeks non-cluster bisa lebih optimal?

Di bawah ini adalah contoh struktur tabel yang saya kerjakan:

Tabel-

Retailers (
    RetailerID int PK, 
    name ...)

Retailer_Relation_Types (
    RelationType smallint PK, 
    Description nvarchar(50) ...)

Retailer_Relations (
    RetailerID int PK FK, 
    RelatedRetailerID int PK FK, 
    RelationType smallint PK FK, 
    CreatedOn datetime ...)

Tabel ini Retailer_Relationsmemiliki indeks PK komposit berikut dan indeks yang disarankan-

CONSTRAINT PK_Retailer_Relations 
PRIMARY KEY CLUSTERED (
    RetailerID ASC, 
    RelatedRetailerID ASC, 
    RelationType ASC
    ) ON [PRIMARY]

CREATE NONCLUSTERED INDEX <NameOfIndex> 
ON Retailer_Relations (
    RetailerID, 
    RelationType
    ) 
INCLUDE (
    RelatedRetailerID
    )
Fletch
sumber

Jawaban:

12

Tabel Retailer_Relations memiliki indeks PK komposit berikut dan indeks yang disarankan

Meskipun indeks yang hilang dapat membantu dan pasti dapat bekerja, saya tidak akan menghabiskan terlalu banyak waktu untuk indeks yang hilang, petunjuk ini dibuat pada perkiraan rencana eksekusi, bukan pada rencana eksekusi yang sebenarnya.

Lebih tepatnya, petunjuk indeks ini didasarkan pada premis untuk mengurangi biaya Query Bucks ™ yang digunakan oleh operator dalam paket tersebut. Pengoptimal menghitung perkiraan biaya, dan menambahkan petunjuk indeks yang hilang sesuai.

Akibatnya mereka bisa sangat salah. Jika Anda tidak yakin apakah itu akan membantu, hal terbaik untuk dilakukan adalah menguji situasi sebelum dan sesudah. Anda bisa melakukan ini dengan menambahkan pernyataan SET STATISTICS IO, TIME ON;sebelum menjalankan kueri.

Anda juga dapat menggunakan statistikparser untuk mempermudah membaca statistik ini.

Mungkinkah ini karena urutan kolom dalam indeks?

Itu benar, membuat indeks yang hilang dapat meningkatkan selektivitas pada kueri, misalnya jika kueri Anda terlihat seperti ini:

SELECT  RelatedRetailerID
FROM Retailer_Relations 
WHERE
RetailerID = 5 AND
RelationType = 20;

atau seperti ini:

SELECT  RelatedRetailerID
FROM Retailer_Relations 
ORDER BY
RetailerID,
RelationType;

Alasan di balik ini adalah bahwa kedua indeks dapat mencari di RetailerID, bagian itu tidak akan berubah. Tetapi bagaimana jika filter / pemesanan tambahan diterapkan pada RelationType? Itu akan menjadi semua tempat di indeks berkerumun, sebagai akibat dari itu menjadi nilai kunci ketiga, bukan nilai kunci kedua. Dan seperti yang kita tahu, itu adalah nilai kunci kedua di NCI.

Oke, tetapi kapan atau bagaimana indeks nonclustered meningkatkan kueri?

Beberapa kasus bisa:

  • Jika relationType memfilter banyak nilai, sisa I / O bisa tinggi, sehingga menghasilkan kebutuhan indeks yang tidak tercakup (Pertanyaan # 1)
  • Pemesanan pada dua kolom terjadi (Satu arah), dan resultset besar (Query # 2).
  • Seperti yang disebutkan @AaronBertrand: jika perbedaan ukuran CI dibandingkan dengan NCI adalah jumlah yang cukup besar, menambahkan NCI akan mengurangi halaman yang dibaca oleh pertanyaan yang mendapat manfaat darinya.

Catatan NCI

Sebagai catatan tambahan, menambahkan kolom kunci ke daftar sertakan dalam NCI Anda tidak benar-benar diperlukan, karena kolom kunci CI secara otomatis termasuk dalam semua indeks Non-clustered.

Anda dapat memilih untuk melakukannya jika Anda tidak yakin apakah indeks berkerumun akan tetap sama, dan ingin kolom selalu disertakan.

Mengenai kueri itu sendiri, jika Anda menambahkan rencana eksekusi melalui PasteThePlan, kami dapat memberikan beberapa informasi lebih lanjut tentang pengindeksan / peningkatan kueri.


Pengujian

Buat tabel dan tambahkan beberapa baris

CREATE TABLE Retailer_Relations (
    RetailerID int , 
    RelatedRetailerID int , 
    RelationType smallint, 
    CreatedOn datetime,
    CONSTRAINT PK_Retailer_Relations 
PRIMARY KEY CLUSTERED (
    RetailerID ASC, 
    RelatedRetailerID ASC, 
    RelationType ASC
    ) ON [PRIMARY])


    DECLARE @I Int = 1
    WHILE @I < 1000
    BEGIN
    INSERT INTO Retailer_Relations(RetailerID,RelatedRetailerID,RelationType,CreatedOn)
    VALUES(@I,@I,@I,GETDATE()
    )
    set @I += 1
    END

Pertanyaan # 1

    SELECT  RelatedRetailerID
FROM Retailer_Relations 
WHERE
RetailerID = 5 AND
RelationType = 20;

Rencanakan tanpa indeks Di Sini

Sementara itu melakukan pencarian, itu melakukan pencarian di RetailerID. Setelah itu mengeluarkan predikat I / O residual pada RelationType

Tambahkan indeks

CREATE NONCLUSTERED INDEX IX_TEST
ON Retailer_Relations (
    RetailerID, 
    RelationType
    ) 
INCLUDE (
    RelatedRetailerID
    )

Predikat residual hilang, semuanya terjadi dalam predikat pencarian, di kedua kolom.

Rencana eksekusi

Dengan kueri kedua, indeks tambah bermanfaat menjadi lebih jelas:

SELECT  RelatedRetailerID
FROM Retailer_Relations 
ORDER BY
RetailerID,
RelationType;

Paket tanpa indeks, dengan operator Sortir:

masukkan deskripsi gambar di sini

Paket dengan indeks, menggunakan indeks menghapus operator sortir

masukkan deskripsi gambar di sini

Randi Vertongen
sumber
1
Terima kasih Randi, saya akan menandai ini sebagai jawaban tetapi hanya ingin bertanya apakah Anda mengatakan saran Indeks Hilang didasarkan pada Rencana Eksekusi yang Diperkirakan? Saya bertanya ini seperti yang ditampilkan dalam Rencana Eksekusi Aktual di SS2016.
Fletch
1
Saya bertanya-tanya apakah itu yang Anda katakan, terima kasih sudah menjelaskan.
Fletch