2013-04-09 56 views
1

鉴于以下 -的MySQL索引

drop table if exists learning_indexes; 

create table learning_indexes (
    id INT NOT NULL, 
    col1 CHAR(30), 
    col2 CHAR(30), 
    col3 CHAR(30), 
    PRIMARY KEY (id), 
    index idx_col1 (col1), 
    index idx_col1_col2 (col1,col2) 
); 

explain 

select 
    col1,col2 
from 
    learning_indexes 
where 
    col1 = 'FOO' 
    and col2 = 'BAR' 

为什么MySQL的挑idx_col1超过idx_col1_col2?

+----+-------------+------------------+------+------------------------+----------+---------+-------+------+-------------+ 
| id | select_type | table   | type | possible_keys   | key  | key_len | ref | rows | Extra  | 
+----+-------------+------------------+------+------------------------+----------+---------+-------+------+-------------+ 
| 1 | SIMPLE  | learning_indexes | ref | idx_col1,idx_col1_col2 | idx_col1 | 91  | const | 1 | Using where | 
+----+-------------+------------------+------+------------------------+----------+---------+-------+------+-------------+ 

这是我的版本信息 -

+-------------------------+---------------------+ 
| Variable_name   | Value    | 
+-------------------------+---------------------+ 
| innodb_version   | 1.1.8    | 
| protocol_version  | 10     | 
| slave_type_conversions |      | 
| version     | 5.5.29    | 
| version_comment   | Source distribution | 
| version_compile_machine | i386    | 
| version_compile_os  | osx10.7    | 
+-------------------------+---------------------+ 

回答

0

我同意Floaf的观点,MySQL有时会选择错误的索引,但我不认为这是这种情况。 MySQL将行数和数据结构包含在决定选择哪个索引中。

对于这样一个相当简单的查询,如果表中包含的行少于100行或者甚至为空,那么MySQL可能不会使用任何索引。扫描所有表格行比使用索引似乎在计算上更便宜。在您的解释计划中,您可以看到“key”列中显示idx_col1,但“Extra”列中没有显示“使用索引”。

如果表中包含超过约100行,MySQL将开始使用idx_col1。解释计划会告诉你这个。只有当col1中实际包含字符串'FOO'的行数超过100行时,MySQL才会注意到使用idx_col1并没有足够的减少临时结果集,因为它必须扫描剩余的100行以获取值' BAR'in col2。因此,它将切换到idx_col1_col2。我不完全确定MySQL如何快速决定使用哪个索引,但我认为它与启发式和索引中各行的基数有关,即索引行的“有选择性”是如何实现的。

+0

谢谢。我认为“使用索引”意味着它从索引中检索选择值?尝试两种变体,注释掉idx_col1。另外,将“col1,col2”切换为*。你能分享你从哪里得到100行信息​​吗? – 2013-04-10 17:03:48

+0

MySQL Doc说,如果Extra列使用where AND使用索引,则表示索引正在用于执行关键值查找(http://dev.mysql.com/doc/refman/5.5/en/explain-output的.html#讲解联接类型)。 – Marcellus 2013-04-10 17:48:09

+0

对于100(或更多)行数据,我将id设为auto_increment主键。然后我添加了3行随机值。为了相乘,我做了一些像INSERT INTO'learning_indexes'(col1,col2,col3)SELECT CONCAT(col2,'q'),CONCAT(col1,'z'),CONCAT(col3,'c')FROM'learning_indexes' ;反复。这会使每次执行的行数加倍,并以某种方式洗牌并修改新插入的行值。 – Marcellus 2013-04-10 17:53:56

0

我不能在这里解释一下你的情况,但有时MySQL的只是选择了“错误”的指标。也许数据库足够小,以至于在这种情况下它不会有任何区别。

这个查询非常简单,它应该理解哪个索引是最合适的。

我可以说经验,当查询变得越来越复杂,特别是当表变得非常大时,MySQL有时(随机?)决定选择另一个索引,然后去查询,然后查询可以从0.01秒到100+秒,所以如果您知道哪个索引是正确的,请使用FORCE INDEX()。即使您使用USE INDEX(),MySQL有时也会选择另一个具有各种致命结果的索引来提高查询速度。