Melihat rencana eksekusi permintaan yang berjalan lambat dan saya perhatikan bahwa beberapa node adalah pencarian indeks dan beberapa dari mereka adalah scan indeks.
Apa perbedaan antara pencarian indeks dan pemindaian indeks?
Yang berkinerja lebih baik?
Bagaimana SQL memilih satu dari yang lain?
Saya menyadari ini adalah 3 pertanyaan tetapi saya pikir menjawab yang pertama akan menjelaskan yang lain.
Jawaban:
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 permintaancol2
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 indekscol2=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 denganINCLUDE
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 karenac1=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 atauVARCHAR(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
atauJOIN ... 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 memintaTOP
agen untuk baris yang pada gilirannya memintaTABLE SCAN
agen untuk satu, kemudianSELECT
agen meminta yang lain tetapiTOP
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.sumber
Secara umum, usahanya baik, pemindaian buruk.
Mencari di mana kueri dapat menggunakan indeks secara efektif, dan menggunakannya untuk menemukan baris yang dibutuhkannya.
Pemindaian adalah di mana kueri mencari melalui seluruh indeks mencoba menemukan apa yang dibutuhkannya.
Bagaimana cara SQL memilih? Jauh di dalam internal optimizer kueri, keputusan dibuat berdasarkan kueri Anda dan indeks yang tersedia dan informasi statistik yang terkait dengan indeks tersebut.
Ada beberapa buku untuk dibaca yang mungkin menarik di sini - Keduanya dari toko buku Gerbang Merah di http://www.red-gate.com/community/books/
sumber
Jika Anda ingin menggali subjek, buku yang sangat membantu (setidaknya bagi saya) adalah Rencana Eksekusi SQL Server oleh Grant Fritchey, tersedia secara bebas di RedGate di sini .
Jika Anda memiliki pertanyaan seperti
SQL Server kemungkinan akan menggunakan pemindaian Indeks, karena harus melalui semua baris untuk menampilkan hasil yang diperlukan.
Di sisi lain,
pasti akan menghasilkan pencarian Indeks. SQL Server akan menggunakan struktur B-tree dari indeks myID dan mengambil baris yang tepat akan jauh lebih cepat.
sumber
Yang lain telah mendefinisikan dengan cukup baik perbedaan antara mencari dan memindai. Dalam hal ini, permintaan Anda sendiri dan perencana pelaksanaan harus memberi Anda informasi yang Anda butuhkan untuk melihat nilai mana yang digunakan sebagai predikat (filter) untuk permintaan di setiap bagian. Biasanya ini merupakan praktik yang baik untuk selalu menambahkan indeks non-clustered pada kunci asing, dan tergantung pada kasus penggunaan dalam kode program, Anda mungkin ingin melihat ke dalam membuat indeks multi-kolom tambahan atau memasukkan indeks kolom juga. Dengan terminologi yang disajikan di sini, pencarian google akan memberikan hasil yang layak pada contoh masing-masing.
Tetapi sebagai contoh, katakan kode Anda meminta Kolom A dan Kolom B pada filter yang diberikan, tetapi Anda juga ingin mengembalikan nilai-nilai Kolom C dan Kolom E, Anda mungkin ingin membuat indeks pada Kolom A dan B dengan TERMASUK opsi yang berisi Kolom C dan E. Dengan cara itu pencarian indeks tunggal akan mengembalikan semua yang Anda butuhkan, karena tidak perlu melakukan pencarian untuk mengambil nilai-nilai lain (C dan E) pada baris yang sama.
sumber