Saya telah menggunakan indeks pada database MySQL saya untuk sementara waktu sekarang tetapi tidak pernah mempelajarinya dengan benar . Secara umum saya menempatkan indeks pada bidang apa pun yang akan saya cari atau pilih menggunakan WHERE
klausa tetapi kadang-kadang tidak tampak begitu hitam dan putih.
Apa praktik terbaik untuk indeks MySQL?
Contoh situasi / dilema:
Jika sebuah tabel memiliki enam kolom dan semuanya dapat dicari, haruskah saya mengindeks semuanya atau tidak sama sekali?
Apa dampak negatif kinerja pengindeksan?
Jika saya memiliki kolom VARCHAR 2500 yang dapat dicari dari bagian situs saya, haruskah saya mengindeksnya?
mysql
indexing
query-optimization
Haroldo
sumber
sumber
Jawaban:
Anda pasti harus meluangkan waktu membaca indeks, ada banyak yang ditulis tentang itu, dan penting untuk memahami apa yang terjadi.
Secara umum, suatu indeks memaksakan pemesanan pada baris-baris tabel.
Demi kesederhanaan, bayangkan sebuah tabel hanyalah file CSV besar. Setiap kali baris dimasukkan, itu dimasukkan di akhir . Jadi urutan "alami" dari tabel hanyalah urutan memasukkan baris.
Bayangkan Anda memiliki file CSV yang dimuat dalam aplikasi spreadsheet yang sangat sederhana. Yang dilakukan spreadsheet ini hanyalah menampilkan data, dan menomori baris dalam urutan yang berurutan.
Sekarang bayangkan Anda perlu menemukan semua baris yang memiliki nilai "M" di kolom ketiga. Mengingat apa yang Anda miliki, Anda hanya memiliki satu opsi. Anda memindai tabel memeriksa nilai kolom ketiga untuk setiap baris. Jika Anda memiliki banyak baris, metode ini ("pemindaian tabel") dapat memakan waktu lama!
Sekarang bayangkan bahwa selain tabel ini, Anda punya indeks. Indeks khusus ini adalah indeks nilai di kolom ketiga. Indeks mencantumkan semua nilai dari kolom ketiga, dalam urutan yang bermakna (katakanlah, menurut abjad) dan untuk masing-masingnya, memberikan daftar nomor baris di mana nilai itu muncul.
Sekarang Anda memiliki strategi yang baik untuk menemukan semua baris di mana nilai kolom ketiga adalah "M". Misalnya, Anda dapat melakukan pencarian biner ! Sedangkan pemindaian tabel mengharuskan Anda untuk mencari N baris (di mana N adalah jumlah baris), pencarian biner hanya mengharuskan Anda melihat entri indeks log-n, dalam kasus yang paling buruk. Wow, itu pasti jauh lebih mudah!
Tentu saja, jika Anda memiliki indeks ini, dan Anda menambahkan baris ke tabel (pada akhirnya, karena itulah cara kerja tabel konseptual kami), Anda perlu memperbarui indeks setiap waktu. Jadi Anda melakukan lebih banyak pekerjaan saat Anda sedang menulis baris baru, tetapi Anda menghemat banyak waktu ketika Anda mencari sesuatu.
Jadi, secara umum, pengindeksan membuat tradeoff antara efisiensi baca dan efisiensi menulis. Tanpa indeks, sisipan bisa sangat cepat - mesin database hanya menambahkan baris ke tabel. Saat Anda menambahkan indeks, mesin harus memperbarui setiap indeks saat melakukan memasukkan.
Di sisi lain, membaca menjadi jauh lebih cepat.
Semoga itu mencakup dua pertanyaan pertama Anda (seperti yang sudah dijawab orang lain - Anda perlu menemukan keseimbangan yang tepat).
Skenario ketiga Anda sedikit lebih rumit. Jika Anda menggunakan LIKE, mesin pengindeksan biasanya akan membantu kecepatan baca Anda hingga "%" pertama. Dengan kata lain, jika Anda MEMILIH kolom MANA SEPERTI 'foo% bar%', database akan menggunakan indeks untuk menemukan semua baris tempat kolom dimulai dengan "foo", dan kemudian perlu memindai rowset perantara tersebut untuk menemukan subset yang mengandung "bar". PILIH ... DI MANA kolom SEPERTI '% bar%' tidak dapat menggunakan indeks. Saya harap Anda bisa melihat alasannya.
Akhirnya, Anda harus mulai memikirkan indeks pada lebih dari satu kolom. Konsepnya sama, dan berperilaku mirip dengan hal-hal seperti - pada dasarnya, jika Anda memiliki indeks pada (a, b, c), mesin akan terus menggunakan indeks dari kiri ke kanan sebaik mungkin. Jadi pencarian pada kolom a mungkin menggunakan indeks (a, b, c), seperti halnya pada (a, b). Namun, mesin perlu melakukan pemindaian tabel penuh jika Anda mencari di mana WHERE b = 5 AND c = 1)
Semoga ini sedikit membantu, tetapi saya harus menegaskan bahwa sebaiknya Anda menghabiskan beberapa jam untuk mencari artikel bagus yang menjelaskan hal-hal ini secara mendalam. Ini juga merupakan ide yang baik untuk membaca dokumentasi server database khusus Anda. Cara indeks diimplementasikan dan digunakan oleh perencana kueri dapat sangat bervariasi.
sumber
FULLTEXT
indeks? Bisakah mereka membantu dengan kondisi sepertiLIKE '%bar%'
?FULLTEXT
dapat membantu dengan itu permintaan jikabar
adalah "kata".FULLTEXT
menangani kata-kata, bukan substring sembarang (sepertiLIKE
halnya).Lihat presentasi seperti More Mastering the Art of Indexing .
Pembaruan 12/2012: Saya telah memposting presentasi baru saya: Cara Mendesain Indeks, Sungguh . Saya mempresentasikan ini pada Oktober 2012 di ZendCon di Santa Clara, dan pada Desember 2012 di Percona Live London.
Merancang indeks terbaik adalah proses yang harus cocok dengan kueri yang Anda jalankan di aplikasi Anda.
Sulit untuk merekomendasikan aturan tujuan umum tentang kolom mana yang terbaik untuk diindeks, atau apakah Anda harus mengindeks semua kolom, tidak ada kolom, indeks mana yang harus menjangkau beberapa kolom, dll. Itu tergantung pada kueri yang perlu Anda jalankan.
Ya, ada beberapa overhead sehingga Anda tidak perlu membuat indeks dengan sia-sia. Tetapi Anda harus membuat indeks yang memberi manfaat pada kueri yang harus Anda jalankan dengan cepat. Overhead indeks biasanya jauh melebihi manfaatnya.
Untuk kolom yang VARCHAR (2500), Anda mungkin ingin menggunakan indeks FULLTEXT atau indeks awalan:
Perhatikan bahwa indeks konvensional tidak dapat membantu jika Anda mencari kata-kata yang mungkin berada di tengah-tengah varchar panjang itu. Untuk itu, gunakan indeks teks lengkap.
sumber
Saya tidak akan mengulangi beberapa saran bagus di jawaban lain, tetapi akan menambahkan:
Indeks Kompon
Anda dapat membuat indeks gabungan - indeks yang menyertakan banyak kolom. MySQL dapat menggunakannya dari kiri ke kanan . Jadi, jika Anda memiliki:
jika Anda memiliki indeks gabungan yang menyertakan Nama / Kategori / Usia dalam urutan itu, klausa WHERE ini akan menggunakan indeks:
tapi
tidak akan menggunakan indeks itu karena semuanya harus digunakan dari kiri ke kanan.
Menjelaskan
Gunakan Jelaskan / Jelaskan Diperpanjang untuk memahami indeks apa yang tersedia untuk MySQL dan mana yang sebenarnya dipilih. MySQL hanya akan menggunakan SATU kunci per kueri .
Log Permintaan Lambat
Aktifkan log kueri lambat untuk melihat kueri mana yang berjalan lambat.
Kolom Lebar
Jika Anda memiliki kolom lebar di mana PALING perbedaan terjadi pada beberapa karakter pertama, Anda hanya dapat menggunakan karakter N pertama dalam indeks Anda. Contoh: Kami memiliki kolom ReferenceNumber didefinisikan sebagai varchar (255) tetapi 97% dari kasus, nomor referensi adalah 10 karakter atau kurang. Saya mengubah indeks untuk hanya melihat 10 karakter pertama dan sedikit meningkatkan kinerja.
sumber
Apakah Anda mencari pada bidang demi bidang atau beberapa pencarian menggunakan beberapa bidang? Bidang mana yang paling banyak dicari? Apa jenis bidangnya? (Indeks berfungsi lebih baik pada INT daripada pada VARCHAR misalnya) Sudahkah Anda mencoba menggunakan EXPLAIN pada kueri yang sedang dijalankan?
UPDATE dan INSERT akan lebih lambat. Ada juga persyaratan ruang penyimpanan tambahan, tetapi itu biasanya tidak penting akhir-akhir ini.
Tidak, kecuali itu UNIK (yang artinya sudah diindeks) atau Anda hanya mencari kecocokan persis pada bidang itu (tidak menggunakan LIKE atau pencarian teks lengkap mySQL).
Saya biasanya mengindeks bidang yang paling banyak ditanyakan, dan kemudian INTs / BOOLEANs / ENUM bukan bidang yang VARCHARS. Jangan lupa, seringkali Anda perlu membuat indeks pada bidang gabungan, bukan indeks pada bidang individual. Gunakan EXPLAIN, dan periksa log lambat.
sumber
Muat Data Secara Efisien : Indeks mempercepat pengambilan tetapi memperlambat penyisipan dan penghapusan, serta pembaruan nilai dalam kolom yang diindeks. Artinya, indeks memperlambat sebagian besar operasi yang melibatkan penulisan. Ini terjadi karena menulis satu baris memerlukan penulisan tidak hanya baris data, itu juga memerlukan perubahan pada indeks apa pun. Semakin banyak indeks yang dimiliki tabel, semakin banyak perubahan yang harus dilakukan, dan semakin besar penurunan kinerja rata-rata. Sebagian besar tabel menerima banyak pembacaan dan sedikit penulisan, tetapi untuk tabel dengan persentase penulisan yang tinggi, biaya pembaruan indeks mungkin signifikan.
Hindari Indeks : Jika Anda tidak memerlukan indeks tertentu untuk membantu kueri berkinerja lebih baik, jangan buat itu.
Ruang Disk : Indeks membutuhkan ruang disk, dan beberapa indeks juga memiliki lebih banyak ruang. Ini mungkin menyebabkan Anda mencapai batas ukuran tabel lebih cepat daripada jika tidak ada indeks. Hindari indeks sedapat mungkin.
Takeaway: Jangan over index
sumber
Secara umum, indeks membantu mempercepat pencarian basis data, memiliki kelemahan menggunakan ruang disk tambahan dan memperlambat
INSERT
/UPDATE
/DELETE
query. GunakanEXPLAIN
dan baca hasilnya untuk mengetahui kapan MySQL menggunakan indeks Anda.Mengindeks semua enam kolom tidak selalu merupakan praktik terbaik.
(a) Apakah Anda akan menggunakan salah satu kolom tersebut ketika mencari informasi spesifik?
(B) Berapa selektivitas kolom-kolom itu (berapa banyak nilai berbeda yang disimpan, dibandingkan dengan jumlah total catatan pada tabel)?
MySQL menggunakan pengoptimal berbasis biaya, yang mencoba menemukan jalur "termurah" saat melakukan kueri. Dan bidang dengan selektivitas rendah bukan kandidat yang baik.
Sudah dijawab: ruang disk tambahan, kinerja lebih rendah saat memasukkan - perbarui - hapus.
Coba Indeks FULLTEXT .
sumber
1/2) Indeks mempercepat operasi tertentu tetapi memperlambat operasi lain seperti menyisipkan, memperbarui, dan menghapus. Ini bisa menjadi keseimbangan yang bagus.
3) gunakan indeks teks lengkap atau mungkin sphinx
sumber
slow down other operations like insert, update and deletes
Anda dapat menggunakanSTART TRANSACTION;
YOUR CODE HERE;
COMMIT
Yang dapat membantu menghindarislowing down
operasi lain, karena hanya akan memeriksa satu kendala satu kali. Peringatan: Jika Anda menggunakanREPLACE INTO
dan AndaSQL_MODE
<>STRICT_ALL_TABLES
ORTRADITIONAL
TheBulk Load
akan mengabaikan menggantikan ke dalam dan insert duplikat.