2009-08-10 41 views
2

我有another有关为我们的优先级jBPM优化mysql索引的问题。相关指数如下:为什么MySQL使用错误的索引?

| 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在检索定时器时询问两个问题。第一个依赖于综合指数(反向优先和duedate)和第二个对独奏指数。然而,增加的独奏索引时运行此查询时,它优先于正确的:

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) 

需要再查询该指数:

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) 

当取下独奏索引,查询号码1正确执行并且查询2需要一个文件夹。添加独奏索引查询编号2正确执行,查询1需要一个文件夹。

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; 

是hint去使MySQL正确优化这两个查询的唯一途径:

这种不受欢迎的行为可以通过添加索引提示的第一个查询被重写?或者我们做错了什么?

回答

3

尝试按顺序添加索引到(DUEDATE_, REVERSEPRIORITY_)。它仍然会使用filesort(我认为),但行数少得多。

也尝试OPTIMIZE TABLE table_name你的表和CHECK TABLE table_name你的表(所以mysql会重新计算索引值)。

这只是一个受过教育的猜测。

+0

不错的建议,它加快了查询速度,并且当where子句给出一个小的结果集时,它将实际上以正常的负载工作。 虽然有关其他解决方案的详细信息,请参阅下面的“答案”。 – Erik 2009-08-10 20:21:24

0

你是对的,我们甚至可以删除其他指标,只有(duedate,reversepriority)。

看起来,这将使查询排序两列中的where子句所选择的行的MySQL文件夹。

只有排序的查询不需要排序。

然而,我们发现,修改查询:

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; 

并添加REVERSEPRIORITY_列在where子句,因为这样的:

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; 

使得MySQL的使用正确的(组合)指数。

+1

感谢您的意见。请注意:您正试图超越优化器。它现在可能会工作,但并不总是按照您的预期工作。如果你知道得更好,你应该使用提示,而不是在条件下添加人工。 – 2009-08-10 20:31:33

+0

是的,我同意这就是我们正在做的。这样我们可以使用HQL,并提示我们不得不引入SQL。我会把这个决定留给高级开发者,但是:) – Erik 2009-08-11 08:01:12