为什么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”。是的,它应该是条件
。