索引IN和范围

时间:2011-03-09 03:17:12

标签: mysql sql indexing innodb

我需要找到此查询的最佳索引:

SELECT c.id id, type
FROM Content c USE INDEX (type_proc_last_cat)
LEFT JOIN Battles b ON c.id = b.id
WHERE type = 1
    AND processing_status = 1
    AND category IN (13, 19)
    AND status = 4
ORDER BY last_change DESC
LIMIT 100";

表格如下:

mysql> describe Content;
+-------------------+---------------------+------+-----+---------+-------+
| Field             | Type                | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+-------+
| id                | bigint(20) unsigned | NO   | PRI | NULL    |       |
| type              | tinyint(3) unsigned | NO   | MUL | NULL    |       |
| category          | bigint(20) unsigned | NO   |     | NULL    |       |
| processing_status | tinyint(3) unsigned | NO   |     | NULL    |       |
| last_change       | int(10) unsigned    | NO   |     | NULL    |       |
+-------------------+---------------------+------+-----+---------+-------+

mysql> show indexes from Content;
+---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table   | Non_unique | Key_name            | Seq_in_index | Column_name       | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+
| Content |          0 | PRIMARY             |            1 | id                | A         |        4115 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_last_cat  |            1 | type              | A         |           4 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_last_cat  |            2 | processing_status | A         |          20 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_last_cat  |            3 | last_change       | A         |        4115 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_last_cat  |            4 | category          | A         |        4115 |     NULL | NULL   |      | BTREE      |         |
+---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+


mysql> describe Battles;
+---------------------+---------------------+------+-----+---------+-------+
| Field               | Type                | Null | Key | Default | Extra |
+---------------------+---------------------+------+-----+---------+-------+
| id                  | bigint(20) unsigned | NO   | PRI | NULL    |       |
| status              | tinyint(4) unsigned | NO   |     | NULL    |       |
| status_last_changed | int(11) unsigned    | NO   |     | NULL    |       |
+---------------------+---------------------+------+-----+---------+-------+

mysql> show indexes from Battles;
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table   | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Battles |          0 | PRIMARY   |            1 | id          | A         |        1215 |     NULL | NULL   |      | BTREE      |         |
| Battles |          0 | id_status |            1 | id          | A         |        1215 |     NULL | NULL   |      | BTREE      |         |
| Battles |          0 | id_status |            2 | status      | A         |        1215 |     NULL | NULL   |      | BTREE      |         |
+---------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

我得到这样的输出:

mysql> explain
    -> SELECT c.id id, type
    -> FROM Content c USE INDEX (type_proc_last_cat)
    -> LEFT JOIN Battles b USE INDEX (id_status) ON c.id = b.id
    -> WHERE type = 1
    ->     AND processing_status = 1
    ->     AND category IN (13, 19)
    ->     AND status = 4
    -> ORDER BY last_change DESC
    -> LIMIT 100;
+----+-------------+-------+--------+--------------------+--------------------+---------+-----------------------+------+--------------------------+
| id | select_type | table | type   | possible_keys      | key                | key_len | ref                   | rows | Extra                    |
+----+-------------+-------+--------+--------------------+--------------------+---------+-----------------------+------+--------------------------+
|  1 | SIMPLE      | c     | ref    | type_proc_last_cat | type_proc_last_cat | 2       | const,const           | 1352 | Using where; Using index |
|  1 | SIMPLE      | b     | eq_ref | id_status          | id_status          | 9       | wtm_master.c.id,const |    1 | Using where; Using index |
+----+-------------+-------+--------+--------------------+--------------------+---------+-----------------------+------+--------------------------+

问题是Content表的行数。看来MySQL无法在type_proc_last_cat索引中有效地使用last_change和category。如果我切换last_change和category的顺序,则选择的行数较少,但会产生ORDER BY的文件排序,这意味着它会从数据库中提取所有匹配的行。更糟糕的是,因为两个表中都有超过100,000行。

表是InnoDB,因此请记住PRIMARY键附加到每个其他索引。所以上面索引type_proc_last_cat的索引就像它上面的那样(type,processing_status,last_change,category,id)。我知道我可以将Battles的PRIMARY键更改为(id,status)并删除id_status索引(我可能会这样做)。

编辑:类型,类别,processing_status和状态的任何值都小于总值的20%。 last_change和status_last_change是unix时间戳。

编辑:如果我以相反的顺序使用与categorylast_change不同的索引,我会得到:

mysql> show indexes from Content;
+---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table   | Non_unique | Key_name            | Seq_in_index | Column_name       | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+
| Content |          0 | PRIMARY             |            1 | id                | A         |        4115 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_cat_last  |            1 | type              | A         |           6 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_cat_last  |            2 | processing_status | A         |          26 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_cat_last  |            3 | category          | A         |         228 |     NULL | NULL   |      | BTREE      |         |
| Content |          1 | type_proc_cat_last  |            4 | last_change       | A         |        4115 |     NULL | NULL   |      | BTREE      |         |
+---------+------------+---------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+


mysql> explain SELECT c.id id, type FROM Content c USE INDEX (type_proc_cat_last) LEFT JOIN Battles b 
USE INDEX (id_status) ON c.id = b.id WHERE type = 1     AND processing_status = 1     AND category IN (13, 19)     AND status = 4 ORDER BY last_change DESC LIMIT 100;
+----+-------------+-------+-------+--------------------+--------------------+---------+-----------------------+------+------------------------------------------+
| id | select_type | table | type  | possible_keys      | key                | key_len | ref                   | rows | Extra                                    |
+----+-------------+-------+-------+--------------------+--------------------+---------+-----------------------+------+------------------------------------------+
|  1 | SIMPLE      | c     | range | type_proc_cat_last | type_proc_cat_last | 10      | NULL                  |  165 | Using where; Using index; Using filesort |
|  1 | SIMPLE      | b     | ref   | id_status          | id_status          | 9       | wtm_master.c.id,const |    1 | Using where; Using index                 |
+----+-------------+-------+-------+--------------------+--------------------+---------+-----------------------+------+------------------------------------------+

文件包让我担心,因为它告诉我MySQL在排序之前首先拉出所有匹配的行。当有100,000+时,这将是一个大问题。

1 个答案:

答案 0 :(得分:0)

rows中的

EXPLAIN字段未反映实际读取的行数。它反映了可能受影响的行数。此外,它不依赖于LIMIT,因为在计算完计划后会应用LIMIT

所以你不必担心它。

另外我建议您在last_change中交换categorytype_proc_last_cat,以便mysql可以尝试使用最后一个索引部分(last_change)进行排序。