- Kapan saya harus menggunakan indeks komposit dalam database?
- Apa percabangan kinerja dengan menggunakan indeks komposit)?
- Mengapa saya harus menggunakan indeks komposit?
Misalnya, saya punya homes
tabel:
CREATE TABLE IF NOT EXISTS `homes` (
`home_id` int(10) unsigned NOT NULL auto_increment,
`sqft` smallint(5) unsigned NOT NULL,
`year_built` smallint(5) unsigned NOT NULL,
`geolat` decimal(10,6) default NULL,
`geolng` decimal(10,6) default NULL,
PRIMARY KEY (`home_id`),
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
) ENGINE=InnoDB ;
Apakah masuk akal bagi saya untuk menggunakan indeks komposit untuk keduanya geolat
dan geolng
, sehingga:
Saya ganti:
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
dengan:
KEY `geolat_geolng` (`geolat`, `geolng`)
Jika begitu:
- Mengapa?
- Apa percabangan kinerja dengan menggunakan indeks komposit)?
MEMPERBARUI:
Karena banyak orang telah menyatakan itu sepenuhnya tergantung pada kueri yang saya lakukan, di bawah ini adalah permintaan yang paling umum dilakukan:
SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???
PEMBARUAN 2:
Dengan skema database berikut:
CREATE TABLE IF NOT EXISTS `homes` (
`home_id` int(10) unsigned NOT NULL auto_increment,
`primary_photo_group_id` int(10) unsigned NOT NULL default '0',
`customer_id` bigint(20) unsigned NOT NULL,
`account_type_id` int(11) NOT NULL,
`address` varchar(128) collate utf8_unicode_ci NOT NULL,
`city` varchar(64) collate utf8_unicode_ci NOT NULL,
`state` varchar(2) collate utf8_unicode_ci NOT NULL,
`zip` mediumint(8) unsigned NOT NULL,
`price` mediumint(8) unsigned NOT NULL,
`sqft` smallint(5) unsigned NOT NULL,
`year_built` smallint(5) unsigned NOT NULL,
`num_of_beds` tinyint(3) unsigned NOT NULL,
`num_of_baths` decimal(3,1) unsigned NOT NULL,
`num_of_floors` tinyint(3) unsigned NOT NULL,
`description` text collate utf8_unicode_ci,
`geolat` decimal(10,6) default NULL,
`geolng` decimal(10,6) default NULL,
`display_status` tinyint(1) NOT NULL,
`date_listed` timestamp NOT NULL default CURRENT_TIMESTAMP,
`contact_email` varchar(100) collate utf8_unicode_ci NOT NULL,
`contact_phone_number` varchar(15) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`home_id`),
KEY `customer_id` (`customer_id`),
KEY `city` (`city`),
KEY `num_of_beds` (`num_of_beds`),
KEY `num_of_baths` (`num_of_baths`),
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
KEY `account_type_id` (`account_type_id`),
KEY `display_status` (`display_status`),
KEY `sqft` (`sqft`),
KEY `price` (`price`),
KEY `primary_photo_group_id` (`primary_photo_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ;
Menggunakan SQL berikut:
EXPLAIN SELECT homes.home_id,
address,
city,
state,
zip,
price,
sqft,
year_built,
account_type_id,
num_of_beds,
num_of_baths,
geolat,
geolng,
photo_id,
photo_url_dir
FROM homes
LEFT OUTER JOIN home_photos ON homes.home_id = home_photos.home_id
AND homes.primary_photo_group_id = home_photos.home_photo_group_id
AND home_photos.home_photo_type_id = 2
WHERE homes.display_status = true
AND homes.geolat BETWEEN -100 AND 100
AND homes.geolng BETWEEN -100 AND 100
EXPLAIN mengembalikan:
id select_type table type possible_keys key key_len ref rows Extra
----------------------------------------------------------------------------------------------------------
1 SIMPLE homes ref geolat,geolng,display_status display_status 1 const 2 Using where
1 SIMPLE home_photos ref home_id,home_photo_type_id,home_photo_group_id home_photo_group_id 4 homes.primary_photo_group_id 4
Saya tidak begitu mengerti cara membaca perintah EXPLAIN. Apakah ini terlihat baik atau buruk. Saat ini, saya TIDAK menggunakan indeks komposit untuk geolat dan geolng. Haruskah saya menjadi seperti itu?
sumber
WHERE geolat BETWEEN ??? AND ??? AND geolng BETWEEN ??? AND ???
. Ini akan berhenti setelah bidang pertama. Jawaban dari "Question Overflow" menjelaskan alasannya.Bayangkan Anda memiliki tiga pertanyaan berikut:
Kueri I:
Kueri II:
Kueri III:
Jika Anda memiliki indeks terpisah per kolom, ketiga kueri menggunakan indeks. Di MySQL, jika Anda memiliki indeks komposit (
geolat
,geolng
), hanya kueri I dan kueri II (yang menggunakan bagian pertama dari indeks komposit) menggunakan indeks. Dalam kasus ini, permintaan III membutuhkan pencarian tabel penuh.Pada bagian Multiple-Column Indexes manual, secara jelas dijelaskan bagaimana beberapa indeks kolom bekerja, jadi saya tidak ingin mengetik ulang manual.
Dari halaman Manual Referensi MySQL :
Jika Anda menggunakan indeks terpisah untuk kolom geolat dan geolng, Anda memiliki dua indeks berbeda di tabel yang bisa Anda cari sendiri.
Jika Anda menggunakan indeks komposit, Anda hanya memiliki satu indeks untuk kedua kolom:
RRN adalah nomor rekaman relatif (untuk menyederhanakan, Anda bisa mengatakan ID). Dua indeks pertama dihasilkan secara terpisah dan indeks ketiga adalah komposit. Seperti yang Anda lihat, Anda dapat mencari berdasarkan geolng pada komposit karena diindeks oleh geolat, namun dimungkinkan untuk mencari berdasarkan geolat atau "geolat AND geolng" (karena geolng adalah indeks level kedua).
Juga, lihat bagian Bagaimana Cara Menggunakan Indeks MySQL .
sumber
BETWEEN
), tidak ada bidang indeks lebih lanjut yang dipertimbangkan! Jadi indeks komposit tidak lebih baik.Mungkin ada kesalahpahaman tentang apa yang dilakukan indeks komposit. Banyak orang berpikir bahwa indeks komposit dapat digunakan untuk mengoptimalkan permintaan pencarian selama
where
klausa tersebut mencakup kolom yang diindeks, dalam kasus Andageolat
dangeolng
. Mari kita selami lebih dalam:Saya percaya data Anda pada koordinat rumah adalah desimal acak seperti itu:
Karena
geolat
dangeolng
nilai sulit terulang. Indeks komposit menyalageolat
dangeolng
akan terlihat seperti ini:Oleh karena itu kolom kedua dari indeks komposit pada dasarnya tidak berguna ! Kecepatan kueri Anda dengan indeks komposit mungkin akan mirip dengan indeks hanya pada
geolat
kolom.Seperti yang disebutkan oleh Will, MySQL menyediakan dukungan ekstensi spasial . Titik spasial disimpan dalam satu kolom, bukan dua
lat
lng
kolom terpisah . Indeks spasial dapat diterapkan ke kolom seperti itu. Namun, efisiensinya bisa dibesar-besarkan berdasarkan pengalaman pribadi saya. Bisa jadi indeks spasial tidak menyelesaikan masalah dua dimensi tetapi hanya mempercepat pencarian menggunakan R-Trees dengan pemisahan kuadrat .Yang menarik adalah titik spasial menghabiskan lebih banyak memori karena menggunakan angka presisi ganda delapan byte untuk menyimpan koordinat. Koreksi saya jika saya salah.
sumber
Indeks komposit sangat kuat karena:
LAKUKAN INTEGRITAS STRUKTUR
Indeks komposit bukan hanya tipe indeks lainnya; mereka dapat menyediakan struktur PERLU untuk tabel dengan menegakkan integritas sebagai Kunci Utama.
Innodb Mysql mendukung pengelompokan dan contoh berikut menggambarkan mengapa indeks komposit mungkin diperlukan.
Untuk membuat teman tabel (yaitu untuk jaringan sosial) kita perlu 2 kolom:
user_id, friend_id
.Tabel Strcture
Berdasarkan kunci utama (PK) adalah unik dan dengan membuat PK komposit, Innodb akan secara otomatis memeriksa bahwa tidak ada duplikat
user_id, friend_id
saat ada catatan baru ditambahkan. Ini adalah perilaku yang diharapkan karena tidak ada pengguna yang memiliki lebih dari 1 catatan (hubungan hubungan)friend_id = 2
misalnya.Tanpa PK komposit, kami dapat membuat skema ini menggunakan kunci pengganti:
Sekarang, setiap kali catatan baru ditambahkan, kami harus memeriksa bahwa catatan sebelumnya dengan kombinasi
user_id, friend_id
tersebut belum ada.Dengan demikian, indeks komposit dapat menegakkan integritas struktur.
Aktifkan penyortiran pada ID yang difilter
Sangat umum untuk mengurutkan satu set catatan berdasarkan waktu posting (timestamp atau datetime). Biasanya, ini berarti memposting pada id yang diberikan. Berikut ini sebuah contoh
Tabel User_Wall_Posts (pikirkan jika posting dinding Facebook)
Kami ingin meminta dan menemukan semua posting untuk
user_id = 10
dan mengurutkan posting komentar berdasarkantimestamp
(tanggal).SQL QUERY
PK komposit memungkinkan Mysql untuk memfilter dan mengurutkan hasil menggunakan indeks; Mysql tidak harus menggunakan file sementara atau filesort untuk mengambil hasilnya. Tanpa kunci komposit, ini tidak akan mungkin dan akan menyebabkan permintaan yang sangat tidak efisien.
Dengan demikian, kunci komposit sangat kuat dan cocok lebih dari masalah sederhana "Saya ingin mencari
column_a, column_b
jadi saya akan menggunakan kunci komposit. Untuk skema database saya saat ini, saya memiliki banyak kunci komposit sebagai kunci tunggal. Jangan mengabaikan Penggunaan kunci komposit!sumber
Indeks komposit berguna untuk
Indeks komposit tidak dapat menangani dua rentang. Saya membahas hal ini lebih lanjut dalam buku resep saya .
Cari terdekat - Jika pertanyaannya adalah benar-benar tentang optimalisasi
maka tidak ada indeks yang benar-benar dapat menangani kedua dimensi.
Sebaliknya, seseorang harus 'berpikir di luar kotak'. Jika satu dimensi diimplementasikan melalui partisi dan yang lain diimplementasikan dengan memilihnya dengan hati-hati
PRIMARY KEY
, yang satu bisa mendapatkan efisiensi yang jauh lebih baik untuk tabel lat / lng lookup yang sangat besar. Blog latlng saya membahas detail tentang bagaimana menerapkan "find terdekat" di dunia. Ini termasuk kode.The
PARTITIONs
garis-garis rentang lintang. YangPRIMARY KEY
sengaja dimulai dengan garis bujur sehingga baris yang berguna cenderung berada di blok yang sama. Stored Rutin mengatur kode berantakan untuk melakukanorder by... limit...
dan untuk menumbuhkan 'kotak' di sekitar target sampai Anda memiliki cukup kedai kopi (atau apa pun). Ini juga menangani perhitungan lingkaran besar dan menangani garis data dan kutub.Lebih
Saya telah menulis blog lain; itu membandingkan 5 cara melakukan pencarian lat / lng: http://mysql.rjweb.org/doc.php/latlng#representation_choices (Ini merujuk tautan yang diberikan di atas sebagai salah satu dari 5.) Salah satu cara lain adalah ini, dan itu menunjukkan bahwa mereka optimal untuk kasus tertentu :
Artinya, memiliki kedua kolom dalam dua indeks, dan tidak memiliki indeks satu kolom pada geolat dan geolng adalah penting.
sumber
Tidak ada Hitam dan Putih, satu ukuran cocok untuk semua jawaban.
Anda harus menggunakan indeks komposit, ketika beban pekerjaan kueri Anda akan mendapat manfaat dari satu.
Anda perlu membuat profil beban pekerjaan kueri Anda untuk menentukan ini.
Indeks komposit berperan ketika kueri dapat dipenuhi sepenuhnya dari indeks itu.
UPDATE (sebagai tanggapan untuk mengedit pertanyaan diposting): Jika Anda memilih * dari tabel indeks komposit dapat digunakan, mungkin tidak. Anda harus menjalankan EXPLAIN PLAN untuk memastikan.
sumber
Untuk melakukan pencarian spasial, Anda memerlukan algoritma R-Tree , yang memungkinkan pencarian area geografis dengan sangat cepat. Apa yang Anda butuhkan untuk pekerjaan ini.
Beberapa basis data memiliki indeks spasial. Pencarian Google yang cepat menunjukkan bahwa MySQL 5 memilikinya (yang melihat SQL Anda, saya rasa Anda menggunakan MySQL).
sumber
Indeks komposit dapat berguna ketika Anda ingin mengoptimalkan
group by
klausa (lihat artikel ini http://dev.mysql.com/doc/refman/5.0/id/group-by-optimization.html ). Mohon perhatian:sumber
GROUP BY
tidak disebutkan.GROUP BY
tidak disebutkan oleh OP.Saya dengan @Mitch, sepenuhnya bergantung pada pertanyaan Anda. Untungnya, Anda dapat membuat dan menjatuhkan indeks kapan saja, dan Anda dapat menambahkan kata kunci EXPLAIN ke pertanyaan Anda untuk melihat apakah penganalisa permintaan menggunakan indeks.
Jika Anda akan mencari pasangan lat / long yang tepat indeks ini kemungkinan akan masuk akal. Tetapi Anda mungkin akan mencari rumah dalam jarak tertentu dari suatu tempat tertentu, sehingga pertanyaan Anda akan terlihat seperti ini (lihat sumber ):
dan indeks sangat mungkin tidak akan membantu sama sekali. Untuk pertanyaan geospasial, Anda memerlukan sesuatu seperti ini .
Perbarui: dengan permintaan ini:
Penganalisis kueri dapat menggunakan indeks pada geolat saja, atau indeks pada geolng saja, atau mungkin kedua indeks. Saya tidak berpikir itu akan menggunakan indeks komposit. Tetapi mudah untuk mencoba masing-masing permutasi ini pada set data nyata dan kemudian (a) melihat apa yang EXPLAIN katakan kepada Anda dan (b) mengukur waktu kueri yang benar-benar diperlukan.
sumber