我有一个看起来像这样的查询:
SELECT * FROM tablename WHERE condition = 1 ORDER BY id LIMIT 1000;
id
是主键。我在condition
上有一个索引,在id
上有一个索引(我还没有在condition
和id
上添加复合索引)。此查询仅使用condition
索引,而不使用id
索引。
如果我explain
查询,它只会说Using where
。我希望它说filesort
。但是,由于此查询是在不使用索引的情况下进行排序的,因此它必须在使用文件排序。此外,此查询正在超时,这是它正在使用文件排序的另一个线索。如果我在没有order by
的情况下运行查询,则查询不会超时。
为什么有时不说filesort
?我认为在两种情况下都应该使用filesort
,因为查询是如此缓慢。
答案 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可以。