2009-08-10 12 views
2

Ich habe another Frage in Bezug auf die Optimierung von MySQL-Indizes für unsere Priorisierung jBPM. Die relevanten Indizes sehen so aus:Warum verwendet MySQL den falschen Index?

JBPM stellt beim Abrufen von Timern zwei Fragen. Der erste ist abhängig vom kombinierten Index (umgekehrte Priorität und Duedate) und der zweite vom Solo Duedate Index. Wenn jedoch den Solo-Index hinzugefügt hat es Vorrang vor dem richtigen, wenn diese Abfrage ausgeführt wird:

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) 

Dieser Index wird für eine weitere Abfrage benötigt:

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) 

Wenn der Solo-Index zu entfernen, query Nummer 1 wird korrekt ausgeführt und Abfrage 2 benötigt einen Filesort. Das Hinzufügen der Solo-Index-Abfrage Nummer 2 wird korrekt ausgeführt und Abfrage 1 benötigt einen Dateisort.

der einzige Weg,
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; 

Ist der Hinweis zu gehen richtig beiden Abfragen machen MySQL optimieren:

Dieses unerwünschte Verhalten kann durch Hinzufügen eines Index Hinweis auf die ersten Abfrage außer Kraft gesetzt werden? Oder machen wir etwas falsch?

Antwort

3

Versuchen Sie, einen Index zu (DUEDATE_, REVERSEPRIORITY_) in dieser Reihenfolge hinzuzufügen. Es wird immer noch filesort (denke ich), aber auf viel weniger Zeilen.

Versuchen Sie auch OPTIMIZE TABLE table_name Ihre Tabelle und CHECK TABLE table_name Ihre Tabelle (so wird MySQL Indexwerte neu berechnen).

Dies ist alles nur eine begründete Vermutung.

+0

Guter Vorschlag, beschleunigte es die Abfrage und würde tatsächlich mit normaler Last arbeiten, wenn die Where-Klausel eine kleine Ergebnismenge angibt, die filesort schnell sortiert. Siehe meine "Antwort" unten für Details zu einer anderen Lösung, obwohl! – Erik

0

Sie haben Recht, wir können sogar die anderen Indizes entfernen und haben nur (duedate, reversepriority).

Es scheint, dass dies dazu führt, dass MySQL-Dateien die durch die where-Klausel ausgewählten Zeilen im Fall der Abfrage, die beide Spalten sortiert, anordnen.

Die Abfrage, die nur duedate sortiert, muss nicht sortiert werden.

jedoch entdeckten wir, dass die Abfrage ändern:

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; 

und das Hinzufügen der REVERSEPRIORITY_ Spalte in der where-Klausel, die als solche:

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' and timer0_.REVERSEPRIORITY < 0 order by timer0_.REVERSEPRIORITY_ asc, timer0_.DUEDATE_ asc limit 160; 

macht MySQL den richtigen (kombiniert) Index verwenden.

+1

danke für die Eingabe. Bitte beachten Sie: Sie versuchen, den Optimierer zu überlisten. Es könnte jetzt funktionieren, wird aber nicht immer so funktionieren, wie Sie es erwarten. Wenn Sie es besser wissen *, sollten Sie einen Hinweis verwenden, anstatt künstliche Bedingungen hinzuzufügen. –

+0

Ja, ich stimme zu, dass wir das machen. Auf diese Weise können wir HQL verwenden, mit Hinweisen sind wir gezwungen, SQL einzuführen. Ich überlasse die Entscheidung jedoch den Seniorentwicklern :) – Erik

Verwandte Themen