0

データベースで次のクエリを実行しようとしています。

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

3 つのフィールド (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」または「FORCE KEY」を使用すると、カードタイプのインデックスを使用できますが、カードタイプとカードステータスの両方を使用することはできません:

    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 よりも優先されるようです。

4

1 に答える 1

0

IIRC、MySQL は同じクエリで 2 つの異なるインデックスを使用できません。両方のインデックスを利用するには、MySQL はそれらを 1 つにマージする必要があります (マニュアルへのリンク)。このようなマージの例を次に示します ([実行計画の表示] をクリックします)。最初の の「index_merge」に注目してくださいSELECT

免責事項: 上記の情報について、私完全には確信が持てません。

あなたの場合、あなたのヒントにもかかわらず、オプティマイザーは、2番目のテーブルの直接スキャンがインデックスのマージよりも高速であると考えています(テーブルにはおそらく非常に多くの行があるため、非常に大きく、操作にコストがかかるインデックスです)。

私はアドバイスします:

ALTER TABLE ADD INDEX CardTypeStatus (cardtype, cardstatus);

これにより、両方の列にインデックスが作成されます。クエリはおそらくこのインデックスを使用できます。後でインデックスを削除したい場合があります: 列のみを検索する場合でも、クエリは 2 列のインデックスを引き続き使用できます (ただし、列のみを検索する場合はそうではありません)。CardTypecardtypecardstatus

複数列インデックスの詳細: http://dev.mysql.com/doc/refman/5.5/en/multiple-column-indexes.html

于 2012-06-22T13:08:46.247 に答える