简体   繁体   English

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

[英]Very simple mysql query not using index

Sorting of my mySQL table does not use the index and I don't know why. 我的mySQL表的排序不使用索引,我不知道为什么。

I've got: 我有:

CREATE TABLE IF NOT EXISTS `test` (
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  KEY `kk` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

and this: 还有这个:

EXPLAIN SELECT * 
FROM test
ORDER BY a

as well as this 以及这个

EXPLAIN SELECT * 
FROM test
USE INDEX ( kk ) 
ORDER BY a

gives me this: 给我这个:

id select_type table type possible_keys key  key_len ref  rows  Extra
1  SIMPLE      test  ALL  NULL          NULL NULL    NULL 10009 Using filesort

I'd like not to see this filesort, and use the key kk to sort my table. 我不想看到这个文件,并使用密钥kk对我的表进行排序。 What am I doing wrong? 我究竟做错了什么?


Thank you for your posts guys, they answer my question! 谢谢你的帖子,他们回答我的问题! However, now I do not undestand what is meant by "table scan" and "filesort"? 但是,现在我不明白“table scan”和“filesort”的含义是什么? Even if I am selecting all fields and all rows of a table, isn't it faster to sort that table by one column by walking in O(n) the internal tree of the index of that column (and then looking up in the table file the extra columns requested, in O(1) for each row => the index file stores each row's physical position in the table file, or?), than to sort eg by quick sort in O(n * log n) the (potentially) randomly stored rows in the table file, without touching the index? 即使我选择表的所有字段和所有行,通过在O(n)中遍历该列索引的内部树(然后在表中查找)来将该表排序为一列不是更快文件所请求的额外列,在O(1)中为每一行=>索引文件存储每个行在表文件中的物理位置,或?),而不是排序,例如通过快速排序在O(n * log n)中(可能)在表文件中随机存储行,而不触及索引? I guess my understanding of how indexes work in mySQL is wrong. 我想我对mySQL如何在mySQL中工作的理解是错误的。

  1. You're selecting all the rows 您正在选择所有行
  2. You're selecting all columns 您正在选择所有列

Following what I said above - mysql estimates it to be more efficient to use full scan. 按照我上面所说的 - mysql估计使用全扫描更有效。

To get it using index you need to add some WHERE that would limit it to reasonable number of rows returned (say 50) 要使用索引获取它,您需要添加一些WHERE ,将其限制为返回的合理行数(比如50)

@zerkms is correct, by reading all the rows in the table, MySQL decides it's going to have to read the majority of the table anyway so there's no need to read the index as well. @zerkms是正确的,通过读取表中的所有行,MySQL决定它无论如何都必须读取表的大部分,所以也不需要读取索引。 The optimizer changes behavior if you select a subset of the table. 如果选择表的子集,优化程序将更改行为。

For example, I created a table like yours and filled it with 16384 rows, with random integers between 0 and 1000000. Then I tried EXPLAIN for different subsets of the table, first 15% of the table, then 17%, then 19%. 例如,我创建了一个类似于你的表,并用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 |
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+

You can also convince it to use the index by decreasing the columns until you are just selecting the columns of the index. 您还可以通过减少列来说服它使用索引,直到您只选择索引的列。 It'll decide to read the index alone, and not touch the table. 它将决定单独读取索引,而不是触摸表格。 You can define an index with extra columns if you need to, even if those columns are not needed for searching or sorting. 如果需要,可以使用额外列定义索引,即使搜索或排序不需要这些列也是如此。

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 |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+

Since you have no WHERE clause it will do a filesort (table scan) unless the only item you are selecting is from the index. 由于您没有WHERE子句,它将执行文件排序(表扫描),除非您选择的唯一项目来自索引。 This query will use the index. 此查询将使用索引。 See this SQL Fiddle 看到这个SQL小提琴

EXPLAIN SELECT a FROM test ORDER BY a

However if you select a column not in the index (* or b) it will do a file scan. 但是,如果选择不在索引(*或b)中的列,它将执行文件扫描。 Either add a where clause with a covering index or change the columns you are selecting. 添加带有覆盖索引的where子句或更改您选择的列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM