Versi singkat: seek jauh lebih baik
Versi yang lebih singkat: seek umumnya jauh lebih baik, tetapi banyak sekali pencarian (yang disebabkan oleh desain kueri yang buruk dengan sub-kueri berkorelasi buruk misalnya, atau karena Anda membuat banyak kueri dalam operasi kursor atau loop lain) bisa lebih buruk daripada memindai, terutama jika kueri Anda mungkin mengembalikan data dari sebagian besar baris di tabel yang terpengaruh.
Ini membantu untuk mencakup seluruh keluarga untuk operasi pencarian data untuk sepenuhnya memahami implikasi kinerja.
Pemindaian Tabel: Tanpa indeks sama sekali yang relevan dengan permintaan Anda, perencana dipaksa untuk menggunakan pemindaian tabel yang berarti bahwa setiap baris dilihat. Ini dapat menghasilkan setiap halaman yang berkaitan dengan data tabel dibaca dari disk yang sering merupakan kasus terburuk. Perhatikan bahwa untuk beberapa kueri itu akan menggunakan pemindaian tabel bahkan ketika indeks yang berguna hadir - ini biasanya karena data dalam tabel sangat kecil sehingga lebih sulit untuk menelusuri indeks (jika ini adalah kasus Anda akan mengharapkan berencana untuk berubah ketika data tumbuh, dengan asumsi ukuran selektivitas indeks baik).
Pemindaian Indeks dengan Pencarian Baris: Tanpa indeks yang dapat langsung digunakan untuk pencarian ditemukan, tetapi indeks yang berisi kolom yang tepat ada, pemindaian indeks dapat digunakan. Misalnya, jika Anda memiliki tabel besar dengan 20 kolom dengan indeks pada kolom1, col2, col3 dan Anda mengeluarkan SELECT col4 FROM exampletable WHERE col2=616
, dalam hal ini pemindaian indeks untuk permintaan col2
lebih baik daripada memindai seluruh tabel. Setelah baris yang cocok ditemukan maka halaman data harus dibaca ke col4 pickup untuk output (atau bergabung lebih lanjut) yang merupakan tahap "pencarian bookmark" ketika Anda melihatnya dalam rencana kueri.
Pemindaian Indeks tanpa Pencarian Baris: Jika contoh di atas adalah SELECT col1, col2, col3 FROM exampletable WHERE col2=616
maka upaya ekstra untuk membaca halaman data tidak diperlukan: setelah pencocokan baris indeks col2=616
ditemukan, semua data yang diminta diketahui. Inilah sebabnya mengapa Anda terkadang melihat kolom yang tidak akan pernah dicari, tetapi kemungkinan akan diminta untuk output, ditambahkan ke akhir indeks - ini dapat menyimpan pencarian baris. Saat menambahkan kolom ke indeks untuk alasan ini dan hanya alasan ini, tambahkan mereka dengan INCLUDE
klausa untuk memberi tahu mesin bahwa tidak perlu mengoptimalkan tata letak indeks untuk permintaan berdasarkan kolom ini (ini dapat mempercepat pembaruan yang dibuat untuk kolom tersebut) . Pemindaian indeks dapat dihasilkan dari kueri tanpa klausa pemfilteran juga: SELECT col2 FROM exampletable
akan memindai indeks contoh ini alih-alih halaman tabel.
Pencarian Indeks (dengan atau tanpa pencarian baris) : Dalam pencarian tidak semua indeks dipertimbangkan. Untuk kueri SELECT * FROM exampletable WHERE c1 BETWEEN 1234 AND 4567
, mesin kueri dapat menemukan baris pertama yang akan cocok dengan melakukan pencarian berbasis pohon pada indeks, c1
kemudian dapat menavigasi indeks secara berurutan hingga mencapai akhir rentang (ini sama dengan kueri karena c1=1234
mungkin ada banyak baris yang cocok dengan kondisi bahkan untuk =
operasi). Ini berarti bahwa hanya halaman indeks yang relevan (ditambah beberapa yang dibutuhkan untuk pencarian awal) yang perlu dibaca daripada setiap halaman dalam indeks (atau tabel).
Indeks Berkelompok: Dengan indeks berkerumun data tabel disimpan dalam node daun dari indeks itu bukannya dalam struktur tumpukan yang terpisah. Ini berarti bahwa tidak akan pernah perlu ada pencarian baris tambahan setelah menemukan baris menggunakan indeks itu tidak peduli kolom apa yang diperlukan [kecuali Anda memiliki data di luar halaman seperti TEXT
kolom atau VARCHAR(MAX)
kolom yang berisi data panjang].
Anda hanya dapat memiliki satu indeks berkerumun untuk alasan ini [1] , indeks berkerumun adalah tabel Anda alih-alih memiliki struktur tumpukan terpisah, jadi jika Anda menggunakan satu [2] pilih tempat Anda meletakkannya dengan hati-hati untuk mendapatkan keuntungan maksimal.
Perhatikan juga bahwa indeks berkerumun karena "kunci pengelompokan" untuk tabel dan termasuk dalam setiap indeks yang tidak berkerumun di atas tabel, sehingga indeks berkerumun lebar umumnya bukan ide yang baik.
[1] Sebenarnya, Anda dapat secara efektif memiliki beberapa indeks berkerumun dengan menetapkan indeks non-berkerumun yang mencakup atau menyertakan setiap kolom pada tabel, tetapi ini sepertinya akan membuang-buang ruang memiliki dampak kinerja penulisan jadi jika Anda mempertimbangkan untuk melakukannya pastikan kamu benar-benar perlu.
[2] Ketika saya mengatakan "jika Anda menggunakan clustered index", tidak diketahui bahwa itu umumnya direkomendasikan bahwa Anda lakukan memiliki satu di setiap meja. Ada pengecualian seperti pada semua aturan praktis, tabel yang melihat sedikit selain sisipan massal dan bacaan tidak berurutan (tabel pementasan untuk proses ETL mungkin) menjadi contoh counter paling umum.
Poin tambahan: Pemindaian Tidak Lengkap:
Penting untuk diingat bahwa tergantung pada sisa kueri pemindaian tabel / indeks mungkin tidak benar-benar memindai seluruh tabel - jika logika memungkinkan rencana kueri mungkin dapat menyebabkannya dibatalkan lebih awal. Contoh paling sederhana dari ini adalah SELECT TOP(1) * FROM HugeTable
- jika Anda melihat rencana permintaan untuk itu Anda akan melihat bahwa hanya satu baris dikembalikan dari pemindaian dan jika Anda menonton statistik IO ( SET STATISTICS IO ON; SELECT TOP(1) * FROM HugeTable
) Anda akan melihat bahwa itu hanya membaca angka yang sangat kecil halaman (mungkin hanya satu).
Hal yang sama dapat terjadi jika predikat a WHERE
atau JOIN ... ON
klausa dapat dijalankan bersamaan dengan pemindaian yang merupakan sumber jika datanya. Perencana kueri / pelari kadang-kadang bisa sangat pintar dalam mendorong predikat kembali ke sumber data untuk memungkinkan penghentian awal pemindaian dengan cara ini (dan kadang-kadang Anda bisa pandai mengatur ulang kueri untuk membantunya melakukannya!). Sementara data mengalir dari kanan ke kiri sesuai panah pada tampilan rencana kueri standar, logika berjalan dari kiri ke kanan dan setiap langkah (kanan-ke-kiri) tidak perlu dijalankan hingga selesai sebelum langkah berikutnya dapat dimulai. Dalam contoh sederhana di atas jika Anda melihat setiap blok dalam rencana kueri sebagai agen, SELECT
agen meminta TOP
agen untuk baris yang pada gilirannya memintaTABLE SCAN
agen untuk satu, kemudian SELECT
agen meminta yang lain tetapi TOP
agen tahu tidak perlu repot-repot untuk bahkan bertanya kepada pembaca tabel, SELECT
agen mendapat tanggapan "tidak lagi relevan" dan tahu semua pekerjaan dilakukan. Banyak operasi memblokir optimasi semacam ini tentu saja sering kali dalam contoh yang lebih rumit pemindaian tabel / indeks benar - benar membaca setiap baris, tetapi berhati-hatilah untuk tidak sampai pada kesimpulan bahwa pemindaian apa pun pasti merupakan operasi yang mahal.