2013-04-09 58 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有時也會選擇另一個具有各種致命結果的索引來提高查詢速度。