非常简单的mysql查询不使用索引

时间:2013-07-17 23:59:56

标签: mysql

我的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中工作的理解是错误的。

3 个答案:

答案 0 :(得分:16)

  1. 您正在选择所有行
  2. 您正在选择所有列
  3. 按照我上面的说法 - 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子句或更改您选择的列。