Bagaimana saya bisa menghilangkan operator Pencarian Kunci (Clustered) dalam rencana eksekusi saya?
Tabel tblQuotes
sudah memiliki indeks berkerumun (on QuoteID
) dan 27 indeks nonclustered, jadi saya mencoba untuk tidak membuat lagi.
Saya memasukkan kolom indeks berkerumun QuoteID
di kueri saya, berharap itu akan membantu - tapi sayangnya masih sama.
Atau melihatnya:
Inilah yang dikatakan operator Pencarian Kunci:
Pertanyaan:
declare
@EffDateFrom datetime ='2017-02-01',
@EffDateTo datetime ='2017-08-28'
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
IF OBJECT_ID('tempdb..#Data') IS NOT NULL
DROP TABLE #Data
CREATE TABLE #Data
(
QuoteID int NOT NULL, --clustered index
[EffectiveDate] [datetime] NULL, --not indexed
[Submitted] [int] NULL,
[Quoted] [int] NULL,
[Bound] [int] NULL,
[Exonerated] [int] NULL,
[ProducerLocationId] [int] NULL,
[ProducerName] [varchar](300) NULL,
[BusinessType] [varchar](50) NULL,
[DisplayStatus] [varchar](50) NULL,
[Agent] [varchar] (50) NULL,
[ProducerContactGuid] uniqueidentifier NULL
)
INSERT INTO #Data
SELECT
tblQuotes.QuoteID,
tblQuotes.EffectiveDate,
CASE WHEN lstQuoteStatus.QuoteStatusID >= 1 THEN 1 ELSE 0 END AS Submitted,
CASE WHEN lstQuoteStatus.QuoteStatusID = 2 or lstQuoteStatus.QuoteStatusID = 3 or lstQuoteStatus.QuoteStatusID = 202 THEN 1 ELSE 0 END AS Quoted,
CASE WHEN lstQuoteStatus.Bound = 1 THEN 1 ELSE 0 END AS Bound,
CASE WHEN lstQuoteStatus.QuoteStatusID = 3 THEN 1 ELSE 0 END AS Exonareted,
tblQuotes.ProducerLocationID,
P.Name + ' / '+ P.City as [ProducerName],
CASE WHEN tblQuotes.PolicyTypeID = 1 THEN 'New Business'
WHEN tblQuotes.PolicyTypeID = 3 THEN 'Rewrite'
END AS BusinessType,
tblQuotes.DisplayStatus,
tblProducerContacts.FName +' '+ tblProducerContacts.LName as Agent,
tblProducerContacts.ProducerContactGUID
FROM tblQuotes
INNER JOIN lstQuoteStatus
on tblQuotes.QuoteStatusID=lstQuoteStatus.QuoteStatusID
INNER JOIN tblProducerLocations P
On P.ProducerLocationID=tblQuotes.ProducerLocationID
INNER JOIN tblProducerContacts
ON dbo.tblQuotes.ProducerContactGuid = tblProducerContacts.ProducerContactGUID
WHERE DATEDIFF(D,@EffDateFrom,tblQuotes.EffectiveDate)>=0 AND DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <=0
AND dbo.tblQuotes.LineGUID = '6E00868B-FFC3-4CA0-876F-CC258F1ED22D'--Surety
AND tblQuotes.OriginalQuoteGUID is null
select * from #Data
Rencana eksekusi:
Jawaban:
Pencarian kunci dari berbagai rasa terjadi ketika prosesor kueri perlu mendapatkan nilai dari kolom yang tidak disimpan dalam indeks yang digunakan untuk menemukan baris yang diperlukan agar permintaan mengembalikan hasil.
Ambil contoh kode berikut, tempat kami membuat tabel dengan indeks tunggal:
Kami akan memasukkan 1.000.000 baris ke tabel sehingga kami memiliki beberapa data untuk dikerjakan:
Sekarang, kami akan meminta data dengan opsi untuk menampilkan rencana eksekusi "aktual":
Rencana kueri menunjukkan:
Kueri melihat
IX_Table1
indeks untuk menemukan baris denganTable1ID = 5000000
karena melihat indeks itu jauh lebih cepat daripada memindai seluruh tabel mencari nilai itu. Namun, untuk memenuhi hasil kueri, prosesor kueri juga harus menemukan nilai untuk kolom lain dalam tabel; ini adalah tempat "RID Lookup" masuk. Itu terlihat di tabel untuk ID baris (RID di RID Lookup) yang terkait dengan baris yang berisiTable1ID
nilai 500000, memperoleh nilai-nilai dariTable1Data
kolom. Jika Anda mengarahkan mouse ke simpul "RID Lookup" di paket, Anda melihat ini:"Daftar Keluaran" berisi kolom yang dikembalikan oleh Pencarian RID.
Tabel dengan indeks berkerumun dan indeks non-berkerumun membuat contoh yang menarik. Tabel di bawah ini memiliki tiga kolom; ID yang merupakan kunci pengelompokan,
Dat
yang diindeks oleh indeks yang tidak dikelompokkanIX_Table
, dan kolom ketigaOth
,.Ambil kueri contoh ini:
Kami meminta SQL Server untuk mengembalikan setiap kolom dari tabel tempat
Dat
kolom berisi kataTest
. Kami punya beberapa pilihan di sini; kita dapat melihat tabel (yaitu indeks berkerumun) - tetapi itu akan memerlukan pemindaian seluruh hal karena tabel dipesan olehID
kolom, yang tidak memberi tahu kita apa pun tentang baris yang berisiTest
dalamDat
kolom. Opsi lain (dan yang dipilih oleh SQL Server) terdiri dari mencari ke dalamIX_Table1
indeks non-cluster untuk menemukan baris di manaDat = 'Test'
, namun karena kita memerlukanOth
kolom juga, SQL Server harus melakukan pencarian ke dalam indeks yang dikelompokkan menggunakan "Kunci". Operasi pencarian ". Ini adalah rencana untuk itu:Jika kita memodifikasi indeks non-clustered sehingga termasuk yang
Oth
kolom:Kemudian jalankan kembali kueri:
Kita sekarang melihat pencarian indeks non-clustered tunggal karena SQL Server hanya perlu menemukan baris
Dat = 'Test'
di mana dalamIX_Table1
indeks, yang termasuk nilai untukOth
, dan nilai untukID
kolom (kunci utama), yang secara otomatis hadir di setiap non-cluster . indeks berkerumun. Rencana:sumber
Pencarian kunci disebabkan karena mesin memilih untuk menggunakan indeks yang tidak mengandung semua kolom yang Anda coba ambil. Jadi indeks tidak mencakup kolom pada pernyataan select and where.
Untuk menghilangkan pencarian kunci Anda harus menyertakan kolom yang hilang (kolom dalam daftar Output pencarian kunci) = ProducerContactGuid, QuoteStatusID, PolicyTypeID dan ProducerLocationID atau cara lain adalah dengan memaksa permintaan untuk menggunakan indeks cluster sebagai gantinya.
Perhatikan bahwa 27 indeks yang tidak berkerumun di atas meja mungkin buruk untuk kinerja. Saat menjalankan pembaruan, masukkan, atau hapus, SQL Server harus memperbarui semua indeks. Pekerjaan ekstra ini dapat memengaruhi kinerja secara negatif.
sumber
Anda lupa menyebutkan volume data yang terlibat dalam kueri ini. Juga mengapa Anda memasukkan ke tabel temp? Kalau saja Anda perlu menampilkan maka jangan menjalankan pernyataan menyisipkan.
Untuk keperluan kueri ini,
tblQuotes
tidak perlu 27 indeks non-cluster. Dibutuhkan 1 indeks berkerumun dan 5 indeks tidak-berkerumun atau, mungkin 6 indekseks tidak-berkerumun.Kueri ini ingin indeks pada kolom ini:
Saya juga memperhatikan kode berikut:
adalah
NON Sargable
yakni tidak dapat memanfaatkan indeks.Untuk
SARgable
mengubahnya, ubah kode ini menjadi:Untuk menjawab pertanyaan utama Anda, "mengapa Anda mendapatkan kunci Cari":
Anda mendapatkan
KEY Look up
karena beberapa kolom yang disebutkan dalam kueri tidak ada dalam indeks penutup.Anda dapat google dan belajar tentang
Covering Index
atauInclude index
.Dalam contoh saya anggap tblQuotes.QuoteStatusID adalah indeks Non Clustered maka saya juga dapat mencakup DisplayStatus. Karena Anda ingin DisplayStatus di Resultset. Kolom apa pun yang tidak ada dalam indeks dan ada di resultset dapat ditutup untuk menghindari
KEY Look Up or Bookmark lookup
. Ini adalah contoh yang meliputi indeks:** Penafian: ** Ingat di atas hanya contoh saya DisplayStatus dapat ditutupi dengan Non CI lainnya setelah analisis.
Anda juga harus membuat indeks dan mencakup indeks pada tabel lain yang terlibat dalam kueri.
Anda mendapatkan
Index SCAN
juga dalam rencana Anda.Ini dapat terjadi karena tidak ada Indeks di atas meja atau ketika ada volume data yang besar, pengoptimal dapat memutuskan untuk memindai daripada melakukan pencarian indeks.
Ini juga dapat terjadi karena
High cardinality
. Mendapatkan lebih banyak jumlah baris daripada yang dibutuhkan karena kesalahan bergabung. Ini juga bisa diperbaiki.sumber