Saya cuba mengoptimumkan pertanyaan SQL, tetapi saya ingin tahu cara melakukannya dengan betul.
SELECT r0_.* FROM ride r0_ use index (ride_booking_id_IDX) LEFT JOIN booking b1_ ON r0_.booking_id = b1_.id LEFT JOIN spot s2_ ON r0_.from_spot_id = s2_.id LEFT JOIN spot s3_ ON r0_.to_spot_id = s3_.id WHERE b1_.start_at <= '2023-04-21' AND b1_.end_at >= '2023-04-20' AND b1_.paid_at IS NOT NULL AND b1_.cancelled_at IS NULL AND ((s2_.zone_id = 1 OR s3_.zone_id = 1)) AND s2_.type = 'parking';
Di sini, saya memaksa penggunaan indeks (booking_id, from_spot_id, to_spot_id)
, yang menyebabkan pertanyaan dilaksanakan dalam masa 25 saat dari tarikh terdekat dalam kira-kira 100 milisaat!
booking
表大约有 200 万行,而 ride
Meja mempunyai kira-kira 5 juta baris.
Walau bagaimanapun, saya dapat melihatnya mengimbas lebih banyak baris menggunakan pengindeksan paksa:
id | Pilih jenis | Meja | Partition | Taip | Kunci yang mungkin | Kunci | key_len | Rujukan | OK | Ditapis | Tambahan |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | Mudah | b1_ | Skop | Utama, booking_id_end_IDX, booking_id_IDX, booking_id_start_IDX, IDX_E00CEDDEB75363F7, IDX_E00CEDDE37D3107C, IDX_E00CEDDEDEA4208C, booking_paid_at_IDX | IDX_E00CEDDE37D3107C | 6 | 111456 | 6.6 | Gunakan syarat indeks; | ||
Mudah | r0_ | Rujukan | ride_booking_id_IDX | ride_booking_id_IDX | 109 | ector.b1_.id | 1 | 100.0 | |||
Mudah | s2_ | eq_ref | Utama, IDX_B9327A739F2C3FAB, spot_type_IDX | Utama | 4 | ector.r0_.from_spot_id | 1 | 72.52 | Tempat penggunaan | ||
Mudah | s3_ | eq_ref | Utama | Utama | 4 | ector.r0_.to_spot_id | 1 | 100.0 | Tempat penggunaan |
id | Pilih jenis | Meja | Partition | Taip | Kunci yang mungkin | Kunci | key_len | Rujukan | OK | Ditapis | Tambahan |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | Mudah | s2_ | Rujukan | Utama, IDX_B9327A739F2C3FAB, spot_type_IDX | spot_type_IDX | 767 | Malar | 161 | 100.0 | Gunakan syarat indeks | |
1 | Mudah | r0_ | Rujukan | IDX_9B3D7CD0ABAF30D3, IDX_9B3D7CD03301C60, ride_booking_id_IDX, booking_from_spot_to_spot_IDX | IDX_9B3D7CD0ABAF30D3 | 5 | ector.s2_.id | 392 | 100.0 | ||
1 | Mudah | b1_ | eq_ref | Utama, booking_id_end_IDX, booking_id_IDX, booking_id_start_IDX, IDX_E00CEDDEB75363F7, IDX_E00CEDDE37D3107C, IDX_E00CEDDEDEA4208C, booking_paid_at_IDX | Utama | 108 | ector.r0_.booking_id | 1 | 5.0 | Tempat penggunaan | |
1 | Mudah | s3_ | eq_ref | Utama | Utama | 4 | ector.r0_.to_spot_id | 1 | 100.0 | Tempat penggunaan |
Setakat yang saya tahu, tarikh yang saya gunakan untuk dibandingkan dengan start_at
和 end_at
adalah sebab mengapa pertanyaan itu nyata lebih pantas.
Jadi saya cuba mengasingkan bahagian paling perlahan kepada pertanyaan yang lebih kecil:
从预订 b 中选择 *,其中 b.start_at < '2021-01-01' 和 b.end_at > '2021-01-01';
Pada tempahan meja, saya mempunyai dua indeks(start_at)
和 (end_at)
ia membantu pertanyaan ini berjalan dengan lebih pantas apabila anda semakin hampir kepada maksimum dan min (memandangkan indeks akan menapis kebanyakan baris, terdapat sedikit baris yang tinggal) mengimbas).
Namun, apabila saya mengambil nilai rawak cukup jauh pada masa lalu, ia menjadi lebih perlahan. Pertanyaan di atas mengambil masa 10 saat untuk dijalankan kerana ia hanya menggunakan satu daripada dua indeks seperti yang dijangkakan, saya tidak tahu mengapa penjelasan itu tidak muncul untuk merge_index pada pertanyaan yang begitu mudah:
id | Pilih jenis | Meja | Partition | Taip | Kunci yang mungkin | Kunci | key_len | Rujukan | OK | Ditapis | Tambahan |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | Mudah | b | Skop | IDX_E00CEDDEB75363F7,IDX_E00CEDDE37D3107C | IDX_E00CEDDEB75363F7 | 6 | 1147319 | 50 | Gunakan syarat indeks; |
Indeks anda
(id, start_at)
未被选取,因为没有固定的id
boleh dicari.Bergantung pada kes penggunaan anda, anda mungkin perlu
start_at
上创建一个索引,在end_at
上创建另一个索引。之后,一个简单的查询SELECT * from booking b where b.start_at '2021-01-01';
berkuat kuasa serta-merta; bergantung pada kriteria carian, MySQL mungkin menggunakan satu indeks atau kedua-duanya melalui operasi pengoptimuman MERGE INDEX.Jika anda ingin menggunakan satu indeks, anda perlu memilih susunan medan dengan berhati-hati, kerana indeks digunakan dalam susunan yang sama di mana ia ditakrifkan.
EDIT: Selepas pengeditan OP, inilah pendapat saya.
Ini menerangkan perkara dengan baik. Dengan mengandaikan anda
SELECT *
,MySQL将被迫读取整个表。尝试仅选择id
, dalam hal ini kemungkinan besar ia akan menggunakan indeks kerana ia akan menjadi pertanyaan yang diliputi indeks.