Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

PILIH dengan variabel kueri tidak menggunakan INDEXes

Alasannya terletak pada penggunaan ATAU kondisi di DI MANA klausa.

Sebagai ilustrasi, coba jalankan kueri lagi, kali ini hanya dengan id = 5 kondisi, dan dapatkan (Jelaskan keluaran):

+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| id | select_type | table      | type   | possible_keys      | key     | key_len | ref   | rows | Extra          |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
|  1 | PRIMARY     | <derived2> | system | NULL               | NULL    | NULL    | NULL  |    1 |                |
|  1 | PRIMARY     | tree       | const  | PRIMARY,index_both | PRIMARY | 4       | const |    1 |                |
|  2 | DERIVED     | NULL       | NULL   | NULL               | NULL    | NULL    | NULL  | NULL | No tables used |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+

Dan lagi, kali ini hanya dengan parent_id = @last_id OR parent_id = 5 kondisi, dan dapatkan:

+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| id | select_type | table      | type   | possible_keys   | key  | key_len | ref  | rows | Extra          |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
|  1 | PRIMARY     | <derived2> | system | NULL            | NULL | NULL    | NULL |    1 |                |
|  1 | PRIMARY     | tree       | ALL    | index_parent_id | NULL | NULL    | NULL |   10 | Using where    |
|  2 | DERIVED     | NULL       | NULL   | NULL            | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+

MySQL tidak terlalu bagus dalam menangani banyak indeks dalam kueri yang sama. Hal-hal sedikit lebih baik dengan kondisi DAN; seseorang lebih mungkin melihat index_merge pengoptimalan daripada serikat indeks pengoptimalan.

Segalanya membaik seiring dengan kemajuan versi, tetapi saya telah menguji kueri Anda pada versi 5.5 , yang merupakan versi produksi terbaru saat ini, dan hasilnya seperti yang Anda gambarkan.

Untuk menjelaskan mengapa ini sulit, pertimbangkan:dua indeks berbeda akan menjawab dua kondisi kueri yang berbeda. Seseorang akan menjawab untuk id = 5 , yang lainnya untuk parent_id = @last_id OR parent_id = 5 (BTW tidak ada masalah dengan ATAU di dalam yang terakhir, karena kedua istilah ditangani dari dalam indeks yang sama).

Tidak ada indeks tunggal yang dapat menjawab keduanya, dan oleh karena itu FORCE INDEX instruksi diabaikan. Lihat, FORCE INDEX mengatakan MySQL harus menggunakan an indeks di atas pemindaian tabel. Ini tidak berarti harus menggunakan lebih dari satu indeks pada pemindaian tabel.

Jadi MySQL mengikuti aturan dokumentasi di sini. Tapi mengapa ini begitu rumit? Karena untuk menjawab menggunakan kedua indeks tersebut, MySQL harus mengumpulkan hasil dari keduanya, menyimpannya di buffer sementara sambil mengelola yang kedua. Kemudian harus melewati buffer itu untuk menyaring baris yang identik (mungkin beberapa baris cocok untuk semua kondisi). Dan kemudian memindai buffer itu untuk mengembalikan hasilnya.

Tapi tunggu, buffer itu sendiri tidak diindeks. Memfilter duplikat bukanlah tugas yang jelas. Jadi MySQL lebih suka bekerja pada tabel asli dan melakukan pemindaian di sana, dan menghindari semua kekacauan itu.

Tentu saja ini bisa dipecahkan. Para insinyur di Oracle mungkin belum memperbaiki ini (baru-baru ini mereka telah bekerja keras untuk meningkatkan rencana eksekusi kueri), tetapi saya tidak tahu apakah ini dalam tugas TODO, atau apakah itu memiliki prioritas tinggi.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. varchar(20) dan varchar(50) sama?

  2. MYSQL menunjukkan 0 bahkan jika hasilnya tidak ada

  3. Ubah Tabel gagal karena baris memiliki data yang salah - Nilai waktu tanggal salah:'0000-00-00 00:00:00'

  4. MYSQL Nilai GANDA salah terpotong

  5. Mysql kiri bergabung dengan kondisi di tabel kanan