Dlaczego MySQL używa niewłaściwego indeksu?

maminne pytanie dotyczące optymalizacji indeksów mysql dla priorytetyzacji jBPM. Odpowiednie indeksy wyglądają tak:

    | JBPM_TIMER |          1 | JBPM_TIMER_REVERSEPRIORITY__DUEDATE_ |            1 | REVERSEPRIORITY_ | A         |          17 |     NULL | NULL   | YES  | BTREE      |         | 
    | JBPM_TIMER |          1 | JBPM_TIMER_REVERSEPRIORITY__DUEDATE_ |            2 | DUEDATE_         | A         |      971894 |     NULL | NULL   | YES  | BTREE      |         | 
    | JBPM_TIMER |          1 | JBPM_TIMER_DUEDATE_                  |            1 | DUEDATE_         | A         |      971894 |     NULL | NULL   | YES  | BTREE      |         | 

JBPM zadaje dwa pytania podczas pobierania zegarów. Pierwszy zależy od połączonego indeksu (odwrócony priorytet i duedate), a drugi od indeksu solo duedate. Jednak podczas dodawania indeksu solo ma on pierwszeństwo przed poprawnym podczas uruchamiania tego zapytania:

mysql> explain select timer0_.ID_ as col_0_0_ from JBPM_TIMER timer0_ where timer0_.ISSUSPENDED_<>1 and  timer0_.DUEDATE_<='2009-08-17 14:51:06' order  by timer0_.REVERSEPRIORITY_ asc, timer0_.DUEDATE_ asc limit 160;
+----+-------------+---------+-------+---------------------------+---------------------------+---------+------+-------+-----------------------------+
| id | select_type | table   | type  | possible_keys             | key                       | key_len | ref  | rows  | Extra                       |
+----+-------------+---------+-------+---------------------------+---------------------------+---------+------+-------+-----------------------------+
|  1 | SIMPLE      | timer0_ | range | JBPM_TIMER_DUEDATE_       | JBPM_TIMER_DUEDATE_ERIK_T | 9       | NULL | 971894| Using where; Using filesort | 
+----+-------------+---------+-------+---------------------------+---------------------------+---------+------+-------+-----------------------------+
1 row in set (0.00 sec)

Ten indeks jest potrzebny dla innego zapytania:

mysql> explain select timer0_.ID_ as col_0_0_ from JBPM_TIMER timer0_ where (timer0_.EXCEPTION_ is null) and timer0_.ISSUSPENDED_<>1 order by timer0_.DUEDATE_ asc limit 160;
+----+-------------+---------+-------+---------------+---------------------+---------+------+-------+-------------+
| id | select_type | table   | type  | possible_keys | key                 | key_len | ref  | rows  | Extra       |
+----+-------------+---------+-------+---------------+---------------------+---------+------+-------+-------------+
|  1 | SIMPLE      | timer0_ | index | NULL          | JBPM_TIMER_DUEDATE_ | 9       | NULL | 24249 | Using where | 
+----+-------------+---------+-------+---------------+---------------------+---------+------+-------+-------------+
1 row in set (0.00 sec)

Podczas usuwania indeksu solo zapytanie numer 1 jest wykonywane poprawnie, a zapytanie 2 wymaga sortowania plików. Dodanie kwerendy indeksu indeksu solo 2 jest wykonywane poprawnie, a kwerenda 1 wymaga sortowania plików.

To niepożądane zachowanie można przesłonić, dodając wskazówkę do pierwszego zapytania:

explain select timer0_.ID_ as col_0_0_ 
from JBPM_TIMER timer0_ USE INDEX (JBPM_TIMER_REVERSEPRIORITY__DUEDATE_) 
where timer0_.ISSUSPENDED_<>1 and  
    timer0_.DUEDATE_<='2009-08-17 14:51:06' 
order  by timer0_.REVERSEPRIORITY_ asc, timer0_.DUEDATE_ asc 
limit 160;

Czy wskazówka jest jedynym sposobem, aby sprawić, by MySQL poprawnie zoptymalizował oba zapytania? Czy robimy coś złego?

questionAnswers(2)

yourAnswerToTheQuestion