由于WHERE子句中的OR条件,MySQL中的filesort

时间:2010-10-28 15:38:30

标签: mysql

我有这个问题:

SELECT * FROM article
   WHERE (state = 2 OR state = 3) AND category_id = 100
   ORDER BY mod_date DESC

我已经定义了这个索引:

category_id_idx:
state
category_id
mod_date

当我使用EXPLAIN运行查询时,它会返回:

id: 1
select_type: SIMPLE
table: article
type: range
possible_keys: category_id_idx
key: category_id_idx
key_len: 3
ref: (NULL)
rows: 4
Extra: Using where; Using filesort

所以...它正在使用一个文件排序。但是,如果我更改WHERE删除OR并且只允许一个字段,这样:

SELECT * FROM article 
   WHERE state = 2 AND category_id = 100 
   ORDER BY mod_date DESC

然后EXPLAIN返回NO filesort:

id: 1
select_type: SIMPLE
table: article
type: ref
possible_keys: category_id_idx
key: category_id_idx
key_len: 3
ref: const,const
rows: 3
Extra: Using where

任何人都知道为什么?我需要那个OR,有解决方法吗?

2 个答案:

答案 0 :(得分:0)

这对我有意义。这个行为很好地解释了:

http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html

基本上,只有在将所有前面的关键部分与常量进行比较时才能避免使用filesort。由于您按kay第3部分进行排序,并将关键部分2与常量进行比较,但将关键部分3(状态)与2 OR 3进行比较,因此它不是常数,因此MySQL需要为排序执行额外的传递。

例如,考虑一下包含4个索引记录的样本集:

a) [2,100,2010-10-01]
b) [2,100,2010-10-20]
c) [3,100,2010-10-10]
d) [3,100,2010-11-01]

如果你只是在寻找状态2,那么你会想要行b,a在索引中是连续的,避免使用filesort。 如果你只是在寻找状态3,那么你会希望行d,c在索引中是连续的,避免使用filesort。

但是你要求的是状态2 OR 3,这意味着你想要在索引中不连续的行d,b,c,a。这就是需要filesort的原因。

答案 1 :(得分:0)

有一种解决方法,但它需要mysql版本5.1

FORCE {INDEX|KEY}
      [{FOR {JOIN|ORDER BY|GROUP BY}] (index_list)

http://dev.mysql.com/doc/refman/5.1/en/index-hints.html