sql >> Databáze >  >> RDS >> Mysql

SELECT s proměnnými dotazu, které nepoužívají INDEXy

Důvod spočívá v použití OR podmínky v KDE doložka.

Pro ilustraci zkuste spustit dotaz znovu, tentokrát pouze s id = 5 podmínku a get (výstup EXPLAIN):

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

A opět, tentokrát pouze s parent_id = @last_id OR parent_id = 5 podmínku a získejte:

+----+-------------+------------+--------+-----------------+------+---------+------+------+----------------+
| 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 není příliš dobré se zpracováním více indexů ve stejném dotazu. Věci jsou o něco lepší s podmínkami AND; je pravděpodobnější, že uvidíte index_merge optimalizace než sjednocení indexů optimalizace.

Věci se s postupem verzí zlepšují, ale testoval jsem váš dotaz na verzi 5.5 , což je aktuální nejnovější produkční verze a výsledky jsou takové, jaké popisujete.

Chcete-li vysvětlit, proč je to obtížné, zvažte:dva různé indexy budou odpovídat na dvě různé podmínky dotazu. Jeden bude odpovídat za id = 5 , druhý pro parent_id = @last_id OR parent_id = 5 (BTW žádný problém s NEBO uvnitř posledně jmenovaného, ​​protože oba termíny jsou zpracovávány ze stejného indexu).

Neexistuje jediný index, který by odpovídal oběma, a proto FORCE INDEX instrukce je ignorována. Viz FORCE INDEX říká, že MySQL musí používat an index přes skenování tabulky. Neznamená to, že při skenování tabulky musí být použit více než jeden index.

MySQL se tedy řídí pravidly dokumentace zde. Ale proč je to tak složité? Protože abychom mohli odpovědět pomocí obou indexů, musí MySQL shromažďovat výsledky z obou, ukládat je stranou do nějaké dočasné vyrovnávací paměti a zároveň spravovat druhý. Pak je třeba přejít přes tento buffer, aby se odfiltrovaly identické řádky (je možné, že některý řádek vyhovuje všem podmínkám). A pak prohledat vyrovnávací paměť, aby se vrátily výsledky.

Ale počkat, ta vyrovnávací paměť sama o sobě indexována není. Filtrování duplikátů není samozřejmým úkolem. MySQL tedy raději pracuje na původní tabulce a provádí skenování tam a vyhne se všemu tomu nepořádku.

To je samozřejmě řešitelné. Inženýři v Oracle to možná ještě vylepší (nedávno tvrdě pracovali na vylepšení plánů provádění dotazů), ale nevím, jestli je to na úkolu TODO, nebo jestli má vysokou prioritu.




  1. Správné zacházení s dlouhými daty v režimu spánku

  2. SQL pro kontrolu, zda je databáze prázdná (žádné tabulky)

  3. Jak mohu vytáhnout seznam ID z tabulky SQL jako řetězec hodnot oddělených čárkami?

  4. Nasazení vysoce dostupných databází a clusterů pomocí ClusterControl