我的mySQL表的排序不使用索引,我不知道为什么。
我有:
CREATE TABLE IF NOT EXISTS `test` (
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
KEY `kk` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
和此:
EXPLAIN SELECT *
FROM test
ORDER BY a
以及
EXPLAIN SELECT *
FROM test
USE INDEX ( kk )
ORDER BY a
给了我这个:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test ALL NULL NULL NULL NULL 10009 Using filesort
我不想看到这个文件,并使用密钥kk对我的表进行排序。我做错了什么?
感谢您的帖子,他们回答了我的问题!但是,现在我不明白“table scan”和“filesort”的含义是什么?即使我选择表的所有字段和所有行,通过在O(n)中遍历该列索引的内部树(然后在表中查找)来将该表排序为一列不是更快提交请求的额外列,在O(1)中为每一行=>索引文件存储每个行在表文件中的物理位置,或?),而不是排序,例如,通过在O(n * log n)中快速排序(可能)随机存储在表文件中的行,而不触及索引?我想我对mySQL如何在mySQL中工作的理解是错误的。
答案 0 :(得分:16)
按照我上面的说法 - mysql估计使用全扫描更有效。
要使用索引获取它,您需要添加一些WHERE
,将其限制为返回的合理行数(比如50)
答案 1 :(得分:4)
@zerkms是正确的,通过读取表中的所有行,MySQL决定它无论如何都必须读取表的大部分,因此也不需要读取索引。如果选择表的子集,优化程序将更改行为。
例如,我创建了一个类似于你的表,并用16384行填充,随机整数介于0和1000000之间。然后我尝试使用EXPLAIN来表示表的不同子集,首先是表的15%,然后是17%,然后19%。
mysql> EXPLAIN SELECT * FROM test where a < 150000 ORDER BY a;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test | range | kk | kk | 5 | NULL | 2272 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
mysql> EXPLAIN SELECT * FROM test where a < 170000 ORDER BY a;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test | range | kk | kk | 5 | NULL | 2560 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
mysql> EXPLAIN SELECT * FROM test where a < 190000 ORDER BY a;
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+
| 1 | SIMPLE | test | ALL | kk | NULL | NULL | NULL | 16384 | Using where; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+
您还可以通过减少列来说服它使用索引,直到您只选择索引的列。它将决定单独读取索引,而不是触摸表格。如果需要,您可以使用额外列定义索引,即使搜索或排序不需要这些列。
mysql> ALTER TABLE test ADD KEY kk2 (a,b);
mysql> EXPLAIN SELECT a,b FROM test ORDER BY a;
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | test | index | NULL | kk2 | 10 | NULL | 16384 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+
答案 2 :(得分:1)
由于您没有WHERE子句,它将执行文件排序(表扫描),除非您选择的唯一项目来自索引。此查询将使用索引。见SQL Fiddle
EXPLAIN SELECT a FROM test ORDER BY a
但是,如果选择不在索引(*或b)中的列,它将执行文件扫描。添加带有覆盖索引的where子句或更改您选择的列。