为什么MySQL';s`explain`在';正在使用'filesort'?

为什么MySQL';s`explain`在';正在使用'filesort'?,mysql,Mysql,我有一个类似以下内容的查询: SELECT * FROM tablename WHERE condition = 1 ORDER BY id LIMIT 1000; id是主键。我在条件上有一个索引,在id上有一个索引(我还没有在条件和id上添加复合索引)。此查询仅使用条件索引,而不使用id索引 如果我explain查询,它只会使用where显示。我希望它会说filesort。但是,由于此查询是在不使用索引的情况下进行排序,因此它必须使用filesort。此外,此查询正在超时,这是它正在使用f

我有一个类似以下内容的查询:

SELECT * FROM tablename WHERE condition = 1 ORDER BY id LIMIT 1000;
id
是主键。我在
条件
上有一个索引,在
id
上有一个索引(我还没有在
条件
id
上添加复合索引)。此查询仅使用
条件
索引,而不使用
id
索引

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


为什么它有时不说
filesort
?我认为在这两种情况下都应该使用
filesort
,因为查询速度太慢了。

我怀疑问题在于您是按
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)
这是您期待的文件排序


实际上,
选择…
选择。。。order by id
两者返回的顺序相同<代码>按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可以。

我怀疑问题在于您是根据
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)
这是您期待的文件排序


实际上,
选择…
选择。。。order by id
两者返回的顺序相同<代码>按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可以。

我不完全确定您的问题是什么。MySQL需要在运行查询之前决定执行计划。查询是否真的很慢只能在以后运行时确定。不同的数据集产生不同的计划是很正常的。我的问题是MySQL应该能够判断查询需要filesort。如果我运行
explain
,它应该能够告诉我。在本例中,它无法判断查询是否需要文件排序,即使它显然需要文件排序。您如何确定它使用的是文件排序?您是按
id
订购的。该表可能已按
id
顺序排列。或者它可以很容易地对内存中的整数列表进行排序。您可以提到
状态
索引。你是指
条件
索引吗?@Schwern在内存中的排序应该仍然是“filesort”。是的,应该是
条件
。我不完全确定你的问题是什么。MySQL需要在运行查询之前决定执行计划。查询是否真的很慢只能在以后运行时确定。不同的数据集产生不同的计划是很正常的。我的问题是MySQL应该能够判断查询需要filesort。如果我运行
explain
,它应该能够告诉我。在本例中,它无法判断查询是否需要文件排序,即使它显然需要文件排序。您如何确定它使用的是文件排序?您是按
id
订购的。该表可能已按
id
顺序排列。或者它可以很容易地对内存中的整数列表进行排序。您可以提到
状态
索引。你是指
条件
索引吗?@Schwern在内存中的排序应该仍然是“filesort”。是的,它应该是
条件