Mysql
 sql >> Baza danych >  >> RDS >> Mysql

SELECT ze zmiennymi zapytania nie używającymi indeksów

Powód leży w użyciu LUB warunki w GDZIE klauzula.

Aby to zilustrować, spróbuj ponownie uruchomić zapytanie, tym razem tylko z id = 5 warunek i uzyskaj (wyjaśnij dane wyjściowe):

+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+
| 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 |
+----+-------------+------------+--------+--------------------+---------+---------+-------+------+----------------+

I znowu, tym razem tylko z parent_id = @last_id OR parent_id = 5 stan i uzyskaj:

+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| 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 nie radzi sobie zbyt dobrze z obsługą wielu indeksów w tym samym zapytaniu. Sytuacja jest nieco lepsza z warunkami AND; bardziej prawdopodobne jest, że zobaczysz index_merge optymalizacja niż unia indeksów optymalizacja.

Sprawy się poprawiają wraz z rozwojem wersji, ale przetestowałem Twoje zapytanie w wersji 5.5 , który jest w najnowszej wersji produkcyjnej, a wyniki są zgodne z opisem.

Aby wyjaśnić, dlaczego jest to trudne, rozważ:dwa różne indeksy odpowiedzą na dwa różne warunki zapytania. Jeden odpowie za id = 5 , drugi dla parent_id = @last_id OR parent_id = 5 (Przy okazji nie ma problemu z LUB wewnątrz tego ostatniego, ponieważ oba terminy są obsługiwane z tego samego indeksu).

Nie ma jednego indeksu, który może odpowiadać na oba, dlatego FORCE INDEX instrukcja jest ignorowana. Zobacz, FORCE INDEX mówi, że MySQL musi używać an indeks na skan tabeli. Nie oznacza to, że podczas skanowania tabeli musi być używany więcej niż jeden indeks.

Tak więc MySQL postępuje zgodnie z zasadami dokumentacji tutaj. Ale dlaczego jest to takie skomplikowane? Ponieważ aby odpowiedzieć przy użyciu obu indeksów, MySQL musi zbierać wyniki z obu, przechowywać jeden z nich w jakimś tymczasowym buforze podczas zarządzania drugim. Następnie musi przejść przez ten bufor, aby odfiltrować identyczne wiersze (możliwe, że jakiś wiersz spełnia wszystkie warunki). A następnie przeskanować ten bufor, aby zwrócić wyniki.

Ale czekaj, ten bufor sam w sobie nie jest indeksowany. Filtrowanie duplikatów nie jest zadaniem oczywistym. Dlatego MySQL woli pracować na oryginalnej tabeli i wykonywać tam skanowanie, unikając całego tego bałaganu.

Oczywiście można to rozwiązać. Inżynierowie z Oracle mogą jeszcze to poprawić (niedawno ciężko pracowali nad poprawą planów wykonywania zapytań), ale nie wiem, czy jest to zadanie TODO, czy ma wysoki priorytet.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy PHP może sprawdzić poprawność składni SQL bez jej wykonywania?

  2. Sortowanie kolumny ciągów zawierającej liczby w SQL?

  3. Jaki jest najlepszy sposób na stopniowe usuwanie starych wierszy z MySQL?

  4. Railsy z bazą danych w pamięci

  5. ORDER BY ASC z wartościami null na dole