Diberikan contoh berikut:
IF OBJECT_ID('dbo.my_table') IS NOT NULL
DROP TABLE [dbo].[my_table];
GO
CREATE TABLE [dbo].[my_table]
(
[id] int IDENTITY (1,1) NOT NULL PRIMARY KEY,
[foo] int NULL,
[bar] int NULL,
[nki] int NOT NULL
);
GO
/* Insert some random data */
INSERT INTO [dbo].[my_table] (foo, bar, nki)
SELECT TOP (100000)
ABS(CHECKSUM(NewId())) % 14,
ABS(CHECKSUM(NewId())) % 20,
n = CONVERT(INT, ROW_NUMBER() OVER (ORDER BY s1.[object_id]))
FROM
sys.all_objects AS s1
CROSS JOIN
sys.all_objects AS s2
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
ON [dbo].[my_table] ([nki] ASC);
GO
Jika saya mengambil semua catatan yang dipesan oleh [nki]
(Non-clustered index):
SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;
SQL Server Execution Times: CPU time = 266 ms, elapsed time = 493 ms
Pengoptimal memilih indeks berkerumun dan kemudian menerapkan algoritma Urut.
Tetapi jika saya memaksanya untuk menggunakan indeks non-cluster:
SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table WITH(INDEX(IX_my_TABLE));
SET STATISTICS TIME OFF;
SQL Server Execution Times: CPU time = 311 ms, elapsed time = 188 ms
Kemudian ia menggunakan indeks non-clustered dengan Pencarian Kunci:
Jelas jika indeks yang tidak berkerumun diubah menjadi indeks yang meliputi:
CREATE UNIQUE NONCLUSTERED INDEX [IX_my_table]
ON [dbo].[my_table] ([nki] ASC)
INCLUDE (id, foo, bar);
GO
Maka hanya menggunakan indeks ini:
SET STATISTICS TIME ON;
SELECT id, foo, bar, nki FROM my_table ORDER BY nki;
SET STATISTICS TIME OFF;
SQL Server Execution Times: CPU time = 32 ms, elapsed time = 106 ms
Pertanyaan
- Mengapa SQL Server menggunakan indeks berkerumun ditambah algoritma pengurutan alih-alih menggunakan indeks non-berkerumun bahkan jika waktu eksekusi 38% lebih cepat dalam kasus terakhir?
Jawaban:
Karena SQL Server menggunakan pengoptimal berbasis biaya berdasarkan statistik, bukan info runtime.
Selama proses estimasi biaya untuk kueri ini, ia sebenarnya mengevaluasi rencana pencarian, tetapi memperkirakan itu akan membutuhkan lebih banyak usaha. (Catat "Estimasi Biaya Subtree" ketika melayang di atas SELECT dalam rencana eksekusi). Itu belum tentu asumsi yang buruk juga - pada mesin uji saya, rencana pencarian mengambil 6X CPU dari jenis / pemindaian.
Lihatlah ke jawaban Rob Farley tentang mengapa SQL Server mungkin membuat rencana pencarian lebih mahal.
sumber
Jika Anda membandingkan jumlah bacaan yang diperlukan dalam 100.000 pencarian dengan apa yang terlibat dalam melakukan pengurutan, Anda mungkin dengan cepat mendapatkan ide tentang mengapa Pengoptimal Kueri memperkirakan bahwa CIX + Sort akan menjadi pilihan terbaik.
Eksekusi Pencarian akhirnya menjadi lebih cepat karena halaman yang sedang dibaca berada dalam memori (bahkan jika Anda menghapus cache, Anda memiliki banyak baris per halaman, sehingga Anda membaca halaman yang sama berulang-ulang, tetapi dengan jumlah fragmentasi yang berbeda atau tekanan memori yang berbeda dari aktivitas lain, ini mungkin tidak terjadi). Ini benar-benar tidak akan mengambil banyak untuk memiliki CIX + Sort lebih cepat, tetapi apa yang Anda lihat adalah karena biaya membaca tidak mempertimbangkan relatif murahnya memukul halaman yang sama berulang kali.
sumber
Saya telah memutuskan untuk menggali sedikit pada pertanyaan ini dan saya menemukan beberapa dokumen menarik berbicara tentang bagaimana dan kapan menggunakan atau mungkin lebih baik, bukan (memaksa) penggunaan indeks non-cluster.
Seperti yang disarankan per komentar oleh John Eisbrener , salah satu yang paling direferensikan, bahkan di blog lain, adalah artikel yang menarik dari Kimberly L. Tripp:
tetapi ini bukan satu-satunya, jika Anda tertarik, Anda dapat melihat halaman ini:
Seperti yang Anda lihat, semuanya bergerak di sekitar konsep titik kritis .
Dikutip dari artikel KL Tripp
Ketika SQL Server menggunakan indeks non-clustered pada heap, pada dasarnya ia mendapatkan daftar pointer ke halaman-halaman tabel dasar. Kemudian menggunakan pointer ini untuk mengambil baris dengan serangkaian operasi yang disebut Row ID Lookups (RID). Ini berarti bahwa setidaknya, ia akan menggunakan halaman yang dibaca sebanyak jumlah baris yang dikembalikan, dan mungkin lebih banyak lagi. Prosesnya agak mirip dengan indeks berkerumun sebagai tabel dasar, dengan hasil yang sama: lebih banyak dibaca.
Tapi, kapan titik kritis itu terjadi?
Tentu saja karena kebanyakan hal dalam hidup ini, itu tergantung ...
Tidak serius, ini terjadi antara 25% dan 33% dari jumlah halaman dalam tabel, tergantung pada berapa banyak baris per halaman. Tetapi ada lebih banyak faktor yang harus Anda pertimbangkan:
Dikutip dari artikel ITPRoToday
Sekarang jika saya menjalankan pertanyaan saya lagi menggunakan statistik IO:
Kueri kedua membutuhkan lebih banyak bacaan logis daripada yang pertama.
Haruskah saya menghindari indeks non-cluster?
Tidak, indeks berkerumun dapat berguna, tetapi layak untuk mengambil waktu dan melakukan upaya ekstra menganalisis apa yang ingin Anda capai dengannya.
Dikutip dari artikel KL Tripp
sumber