Dua indeks satu kolom vs satu indeks dua kolom di MySQL?

114

Saya dihadapkan pada hal-hal berikut dan saya tidak yakin apa praktik terbaik.

Pertimbangkan tabel berikut (yang akan menjadi besar):

id PK | giver_id FK | penerima_id FK | tanggal

Saya menggunakan InnoDB dan dari apa yang saya pahami, ini membuat indeks secara otomatis untuk dua kolom kunci asing. Namun, saya juga akan melakukan banyak kueri di mana saya perlu mencocokkan kombinasi tertentu dari:

SELECT...WHERE giver_id = x AND recipient_id = t.

Setiap kombinasi tersebut akan unik di tabel.

Apakah ada keuntungan dari menambahkan indeks dua kolom di atas kolom-kolom ini, atau apakah dua indeks individual secara teori cukup / sama?

Tom
sumber
1
Jika kombinasi dua kolom itu unik, Anda dapat membuat indeks dua kolom dengan fitur unik yang tidak hanya akan meningkatkan kecepatan kueri Anda tetapi juga menambah konsistensi ke tabel Anda.
sguven
"MySQL dapat menggunakan indeks beberapa kolom untuk kueri yang menguji semua kolom dalam indeks, atau kueri yang hanya menguji kolom pertama, dua kolom pertama, tiga kolom pertama, dan seterusnya. Jika Anda menentukan kolom di sebelah kanan agar dalam definisi indeks, indeks gabungan tunggal dapat mempercepat beberapa jenis kueri di tabel yang sama. " - Indeks Beberapa Kolom
AlikElzin-kilaka
Untuk mengekstrapolasi pada @ user1585784; Jika kombinasi dari dua kolom itu unik, saya pikir seseorang harus menggunakan kunci unik untuk keduanya. Faktanya, jika seseorang ingin menerapkan keunikan pada level database, kunci unik adalah cara termudah untuk pergi ...
Erk

Jawaban:

133

Jika Anda memiliki dua indeks kolom tunggal, hanya satu di antaranya yang akan digunakan dalam contoh Anda.

Jika Anda memiliki indeks dengan dua kolom, kueri mungkin lebih cepat (Anda harus mengukur). Indeks dua kolom juga dapat digunakan sebagai indeks kolom tunggal, tetapi hanya untuk kolom yang dicantumkan terlebih dahulu.

Terkadang bermanfaat untuk memiliki indeks pada (A, B) dan indeks lain pada (B). Ini membuat kueri yang menggunakan salah satu atau kedua kolom menjadi cepat, tetapi tentu saja menggunakan lebih banyak ruang disk.

Saat memilih indeks, Anda juga perlu mempertimbangkan efek penyisipan, penghapusan, dan pembaruan. Lebih banyak indeks = pembaruan lebih lambat.

Mark Byers
sumber
1
"MySQL dapat menggunakan indeks beberapa kolom untuk kueri yang menguji semua kolom dalam indeks, atau kueri yang hanya menguji kolom pertama, dua kolom pertama, tiga kolom pertama, dan seterusnya. Jika Anda menentukan kolom di sebelah kanan agar dalam definisi indeks, indeks gabungan tunggal dapat mempercepat beberapa jenis kueri di tabel yang sama. " - Indeks Beberapa Kolom
AlikElzin-kilaka
33

Indeks penutup seperti:

ALTER TABLE your_table ADD INDEX (giver_id, recipient_id);

... berarti indeks dapat digunakan jika kueri dirujuk giver_id, atau kombinasi dari giver_iddan recipient_id. Perhatikan bahwa kriteria indeks didasarkan pada paling kiri - kueri yang hanya merujuk pada recipient_idtidak akan dapat menggunakan indeks penutup dalam pernyataan yang saya berikan.

Selain itu, MySQL hanya dapat menggunakan satu indeks per SELECT sehingga indeks penutup akan menjadi cara terbaik untuk mengoptimalkan kueri Anda.

OMG Ponies
sumber
10
MySQL can only use one index per SELECTini tidak benar lagi, alangkah baiknya jika Anda mengedit jawaban Anda untuk diperbarui.
Davor
Maukah Anda menjelaskan mengapa indeks penutup tidak dapat digunakan oleh recipient_id?
Ivo Pereira
2
@IvoPereira Multi kolom indeks di MySQL memungkinkan Anda menggunakan semua bidang dalam indeks dari kiri ke kanan. Misalnya jika Anda memiliki INDEX (col1, col2, col3, col4)maka indeks akan diterapkan untuk pencarian dengan WHEREklausa seperti col1 = 'A'atau col1 = 'A' AND col2 = 'B'atau col1 = 'A' AND col2 ='B' AND col3 = 'C' AND col4 = 'D', tetapi indeks khusus ini tidak akan digunakan untuk hal-hal seperti WHERE col2 = 'B'atau WHERE col3 = 'C' AND col4 = 'D'karena bidang pencarian tidak tersisa dalam definisi indeks. Anda harus menambahkan indeks tambahan untuk menutupi bidang tersebut.
Slicktrick
"satu indeks per PILIH" , apakah ini masih berlaku untuk mariadb 10.1?
oldboy
1
@Anthony: Tidak. Lihat komentar Davor di atas.
kapad
4

Jika salah satu indeks kunci asing sudah sangat selektif, maka mesin database harus menggunakan yang satu itu untuk kueri yang Anda tentukan. Kebanyakan mesin database menggunakan beberapa jenis heuristik untuk dapat memilih indeks yang optimal dalam situasi tersebut. Jika tidak ada indeks yang sangat selektif dengan sendirinya, mungkin masuk akal untuk menambahkan indeks yang dibangun pada kedua kunci karena Anda mengatakan Anda akan sering menggunakan jenis kueri tersebut.

Hal lain yang perlu dipertimbangkan adalah jika Anda dapat menghilangkan bidang PK dalam tabel ini dan menentukan indeks kunci utama pada bidang giver_iddan recipient_id. Anda mengatakan bahwa kombinasinya unik, sehingga mungkin akan berhasil (mengingat banyak kondisi lain yang hanya Anda yang dapat menjawabnya). Biasanya, bagaimanapun, saya pikir kompleksitas tambahan yang menambahkan tidak sebanding dengan kerumitannya.

Mark Wilkins
sumber
Thanks Mark, salah satu kuncinya memang sangat selektif jadi harusnya baik-baik saja. Saya telah memilih untuk mempertahankan dua indeks (otomatis) dan melihat bagaimana kinerjanya dari waktu ke waktu. Saya juga memikirkan tentang pemberi gabungan: kunci utama penerima, tetapi karena setiap bidang juga harus dapat dicari secara individual, itu hanya akan menambahkan overhead php. Juga, kunci baru akan menjadi string (lebih panjang), bukan bilangan bulat (lebih pendek).
Tom
2

Hal lain yang perlu dipertimbangkan adalah bahwa karakteristik kinerja dari kedua pendekatan akan didasarkan pada ukuran dan kardinalitas dataset. Anda mungkin menemukan bahwa indeks 2 kolom hanya menjadi lebih berkinerja pada ambang ukuran kumpulan data tertentu, atau sebaliknya. Tidak ada yang dapat menggantikan metrik kinerja untuk skenario Anda yang sebenarnya.

Andrew
sumber
bisakah Anda menautkan ke beberapa dokumentasi seputar ini. Terima kasih.
kapad