sql >> Databasteknik >  >> RDS >> Mysql

SELECT med frågevariabler som inte använder INDEX

Anledningen ligger i användningen av ELLER förhållandena i VAR klausul.

För att illustrera, försök att köra frågan igen, denna gång med endast id = 5 condition, och få (EXPLAIN output):

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

Och igen, denna gång med endast parent_id = @last_id OR parent_id = 5 skick och få:

+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| 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 är inte så bra med att hantera flera index i samma fråga. Det är något bättre med AND-förhållanden; man är mer sannolikt att se en index_merge optimering än en indexunion optimering.

Saker och ting förbättras allt eftersom versionerna avancerar, men jag har testat din fråga på version 5.5 , som har den senaste produktionsversionen, och resultaten är som du beskriver.

För att förklara varför detta är svårt, överväg:två olika index svarar för två olika villkor för frågan. Man kommer att svara för id = 5 , den andra för parent_id = @last_id OR parent_id = 5 (BTW inga problem med ELLER inuti den senare, eftersom båda termerna hanteras från samma index).

Det finns inget enskilt index som kan svara för båda, och därför FORCE INDEX instruktionen ignoreras. Se FORCE INDEX säger att MySQL måste använda en index över en tabellskanning. Det betyder inte att det måste använda mer än ett index över en tabellskanning.

Så MySQL följer reglerna för dokumentationen här. Men varför är detta så komplicerat? För att svara med båda indexen måste MySQL samla in resultat från båda, lagra ens åt sidan i någon tillfällig buffert medan den andra hanteras. Sedan måste man gå över den bufferten för att filtrera bort identiska rader (det är möjligt att någon rad passar alla villkor). Och sedan skanna den bufferten för att returnera resultaten.

Men vänta, den bufferten är i sig inte indexerad. Att filtrera dubbletter är inte en självklar uppgift. Så MySQL föredrar att arbeta på originaltabellen och göra skanningen där, och undvika allt det där.

Naturligtvis är detta lösbart. Ingenjörerna på Oracle kanske ännu förbättrar detta (på senare tid har de arbetat hårt med att förbättra exekveringsplanerna för frågor), men jag vet inte om detta är på TODO-uppgiften eller om det har hög prioritet.




  1. Geo distans MySQL

  2. Kontrollera om en rad finns, annars infogas

  3. Kan jag använda flera markörer på en anslutning med pyodbc och MS SQL Server?

  4. Hierarkisk data i MySql