为什么MySQL的“ explain”在使用“ filesort”时没有说“ filesort”?

时间:2018-10-11 18:05:56

标签: mysql

我有一个看起来像这样的查询:

SELECT * FROM tablename WHERE condition = 1 ORDER BY id LIMIT 1000;

id是主键。我在condition上有一个索引,在id上有一个索引(我还没有在conditionid上添加复合索引)。此查询仅使用condition索引,而不使用id索引。

如果我explain查询,它只会说Using where。我希望它说filesort。但是,由于此查询是在不使用索引的情况下进行排序的,因此它必须在使用文件排序。此外,此查询正在超时,这是它正在使用文件排序的另一个线索。如果我在没有order by的情况下运行查询,则查询不会超时。

为什么有时不说filesort?我认为在两种情况下都应该使用filesort,因为查询是如此缓慢。

1 个答案:

答案 0 :(得分:2)

我怀疑问题是您正在通过id订购。如果id是一个自动递增的整数,则该表很可能已被id排序。例如...

mysql> describe tablename;
+--------+---------+------+-----+---------+----------------+
| Field  | Type    | Null | Key | Default | Extra          |
+--------+---------+------+-----+---------+----------------+
| id     | int(11) | NO   | PRI | NULL    | auto_increment |
| value  | int(11) | YES  | MUL | NULL    |                |
| status | int(11) | YES  | MUL | NULL    |                |
+--------+---------+------+-----+---------+----------------+

mysql> show indexes from tablename;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| tablename |          0 | PRIMARY  |            1 | id          | A         |      199824 |     NULL | NULL   |      | BTREE      |         |               |
| tablename |          1 | value    |            1 | value       | A         |      101829 |     NULL | NULL   | YES  | BTREE      |         |               |
| tablename |          1 | status   |            1 | status      | A         |           1 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

mysql> explain select * from tablename where status = 1 order by id limit 1000;
+----+-------------+-----------+------------+------+---------------+--------+---------+-------+-------+----------+-----------------------+
| id | select_type | table     | partitions | type | possible_keys | key    | key_len | ref   | rows  | filtered | Extra                 |
+----+-------------+-----------+------------+------+---------------+--------+---------+-------+-------+----------+-----------------------+
|  1 | SIMPLE      | tablename | NULL       | ref  | status        | status | 5       | const | 99912 |   100.00 | Using index condition |
+----+-------------+-----------+------------+------+---------------+--------+---------+-------+-------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

id订购时,没有文件排序。观看当我们通过另一个索引列进行订购时会发生什么...

mysql> explain select * from tablename where status = 1 order by value limit 1000;
+----+-------------+-----------+------------+------+---------------+--------+---------+-------+-------+----------+---------------------------------------+
| id | select_type | table     | partitions | type | possible_keys | key    | key_len | ref   | rows  | filtered | Extra                                 |
+----+-------------+-----------+------------+------+---------------+--------+---------+-------+-------+----------+---------------------------------------+
|  1 | SIMPLE      | tablename | NULL       | ref  | status        | status | 5       | const | 99912 |   100.00 | Using index condition; Using filesort |
+----+-------------+-----------+------------+------+---------------+--------+---------+-------+-------+----------+---------------------------------------+
1 row in set, 1 warning (0.00 sec)

您期望的是文件排序。


实际上,select ...select ... order by id都以相同的顺序返回。 order by id是隐式排序。

mysql> SELECT * FROM tablename WHERE status = 1 order by id LIMIT 1000,10;
+------+-------+--------+
| id   | value | status |
+------+-------+--------+
| 1935 |    12 |      1 |
| 1939 |    59 |      1 |
| 1940 |    56 |      1 |
| 1941 |    21 |      1 |
| 1942 |     5 |      1 |
| 1943 |    68 |      1 |
| 1944 |    65 |      1 |
| 1947 |    27 |      1 |
| 1948 |    44 |      1 |
| 1950 |    75 |      1 |
+------+-------+--------+
10 rows in set (0.01 sec)

mysql> SELECT * FROM tablename WHERE status = 1 LIMIT 1000,10;
+------+-------+--------+
| id   | value | status |
+------+-------+--------+
| 1935 |    12 |      1 |
| 1939 |    59 |      1 |
| 1940 |    56 |      1 |
| 1941 |    21 |      1 |
| 1942 |     5 |      1 |
| 1943 |    68 |      1 |
| 1944 |    65 |      1 |
| 1947 |    27 |      1 |
| 1948 |    44 |      1 |
| 1950 |    75 |      1 |
+------+-------+--------+
10 rows in set (0.00 sec)

您不能依赖此默认顺序,但MySQL可以。