2012-06-22 53 views
0

我試圖跑在我的數據庫以下查詢特定索引:不是MySQL使用

SELECT * FROM ts_cards WHERE (cardstatus= 2 OR cardstatus= 3) AND (cardtype= 1 OR cardtype= 2) ORDER BY cardserial DESC LIMIT 10;

所有三個字段(cardstatus,cardtype和cardserial)被編入索引:

mysql> SHOW INDEX FROM ts_cards; 
    +----------+------------+----------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ 
    | Table | Non_unique | Key_name  | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
    +----------+------------+----------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ 
    | ts_cards |   0 | PRIMARY  |   1 | card_id   | A   | 15000134 |  NULL | NULL |  | BTREE  |   | 
    | ts_cards |   1 | CardID   |   1 | cardserial  | A   | 15000134 |  NULL | NULL |  | BTREE  |   | 
    | ts_cards |   1 | CardType  |   1 | cardtype   | A   |   17 |  NULL | NULL |  | BTREE  |   | 
    | ts_cards |   1 | CardHolder  |   1 | cardstatusholder | A   |   17 |  NULL | NULL |  | BTREE  |   | 
    | ts_cards |   1 | CardExpiration |   1 | cardexpiredstatus | A   |   17 |  NULL | NULL |  | BTREE  |   | 
    | ts_cards |   1 | CardStatus  |   1 | cardstatus  | A   |   17 |  NULL | NULL |  | BTREE  |   | 
    +----------+------------+----------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+ 
    6 rows in set (0.22 sec) 

(是的,我知道索引的名字吸)

但是,默認情況下,MySQL只使用cardstatus的索引:

mysql> EXPLAIN SELECT * FROM `ts_cards` WHERE (cardstatus= 2 OR cardstatus= 3) AND (cardtype= 1 OR cardtype= 2) ORDER BY cardserial DESC LIMIT 10; 
    +----+-------------+----------+-------+---------------------+------------+---------+------+---------+-----------------------------+ 
    | id | select_type | table | type | possible_keys  | key  | key_len | ref | rows | Extra      | 
    +----+-------------+----------+-------+---------------------+------------+---------+------+---------+-----------------------------+ 
    | 1 | SIMPLE  | ts_cards | range | CardType,CardStatus | CardStatus | 1  | NULL | 3215967 | Using where; Using filesort | 
    +----+-------------+----------+-------+---------------------+------------+---------+------+---------+-----------------------------+ 
    1 row in set (0.00 sec) 

(它甚至不考慮cardserial的索引,但我想這是另外一個問題。)

使用「USE KEY」或「力鑰匙」可以使其使用cardtype的指數,但不能同時cardtype和cardstatus:

mysql> EXPLAIN SELECT * FROM `ts_cards` FORCE KEY (CardType) WHERE (cardstatus= 2 OR cardstatus= 3) AND (cardtype= 1 OR cardtype= 2) ORDER BY cardserial DESC LIMIT 10; 
    +----+-------------+----------+-------+---------------+----------+---------+------+---------+-----------------------------+ 
    | id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra      | 
    +----+-------------+----------+-------+---------------+----------+---------+------+---------+-----------------------------+ 
    | 1 | SIMPLE  | ts_cards | range | CardType  | CardType | 1  | NULL | 6084861 | Using where; Using filesort | 
    +----+-------------+----------+-------+---------------+----------+---------+------+---------+-----------------------------+ 
    1 row in set (0.00 sec) 

    mysql> EXPLAIN SELECT * FROM `ts_cards` FORCE KEY (CardType,CardStatus) WHERE (cardstatus= 2 OR cardstatus= 3) AND (cardtype= 1 OR cardtype= 2) ORDER BY cardserial DESC LIMIT 10; 
    +----+-------------+----------+-------+---------------------+------------+---------+------+---------+-----------------------------+ 
    | id | select_type | table | type | possible_keys  | key  | key_len | ref | rows | Extra      | 
    +----+-------------+----------+-------+---------------------+------------+---------+------+---------+-----------------------------+ 
    | 1 | SIMPLE  | ts_cards | range | CardType,CardStatus | CardStatus | 1  | NULL | 3215967 | Using where; Using filesort | 
    +----+-------------+----------+-------+---------------------+------------+---------+------+---------+-----------------------------+ 
    1 row in set (0.00 sec) 

如何強制MySQL使用兩個索引來加快查詢? cardtype和cardstatus索引似乎都以相同的方式定義,但cardstatus似乎優先於cardtype。

回答

0

IIRC,MySQL不能在同一個查詢中使用兩個不同的索引。爲了使用這兩個索引,MySQL需要將它們合併爲一個(link to manual)。如果這樣合併(點擊「查看執行計劃」),這裏是an example。注意第一個SELECT的「index_merge」。

聲明:我是不是絕對確定以上信息。

在你的情況下,儘管你有提示,優化器依然認爲第二個表的直接掃描比合並索引要快(你的表可能有很多行,因此是一個非常大的,操縱指數)。

我建議:

ALTER TABLE ADD INDEX CardTypeStatus (cardtype, cardstatus); 

這將創建兩個列的索引。您的查詢將可能能夠使用此索引。您可能想要在以後放棄您的CardType索引:即使僅在cardtype列上搜索(但如果它們僅在cardstatus上搜索時),查詢仍然可以使用雙列索引。

有關多列索引的更多信息:http://dev.mysql.com/doc/refman/5.5/en/multiple-column-indexes.html