2012-03-09 29 views
12

我命名 '测试' 具有两列一个简单的MySQL表:的MySQL不使用索引的ORDER BY

  1. 自动递增INT列称为 'id'
  2. VARCHAR(3000)列被称为“textcol '

我根据'textcol'列在表格中创建索引。但是,ORDER BY查询似乎没有使用索引,即在textcol上的ORDER BY的简单查询上的EXPLAIN语句在其输出的Key列中显示NULL,并且也使用filesort。

任何进行更改以帮助通过查询为ORDER使用索引的指针都对我很有用。

如通过“的MySQL --version”命令给出

MySQL版本:使用的ReadLine

的MySQL版14.14 DISTRIB 58年5月1日,对于Debian的Linux-GNU(x86_64的)6.2

mysql> CREATE TABLE test (id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY(id), textcol VARCHAR(3000)); 
Query OK, 0 rows affected (0.05 sec) 

mysql> DESCRIBE test; 
+---------+---------------+------+-----+---------+----------------+ 
| Field | Type   | Null | Key | Default | Extra   | 
+---------+---------------+------+-----+---------+----------------+ 
| id  | int(11)  | NO | PRI | NULL | auto_increment | 
| textcol | varchar(3000) | YES |  | NULL |    | 
+---------+---------------+------+-----+---------+----------------+ 
2 rows in set (0.00 sec) 

mysql> CREATE INDEX textcolindex ON test (textcol); 
Query OK, 0 rows affected, 2 warnings (0.06 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

mysql> SHOW INDEX FROM test; 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name  | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
| test |   0 | PRIMARY  |   1 | id   | A   |   0 |  NULL | NULL |  | BTREE  |   | 
| test |   1 | textcolindex |   1 | textcol  | A   |  NULL |  1000 | NULL | YES | BTREE  |   | 
+-------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+ 
2 rows in set (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test1'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test2'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test3'); 
Query OK, 1 row affected (0.00 sec) 

mysql> INSERT INTO test (textcol) VALUES ('test4'); 
Query OK, 1 row affected (0.00 sec) 


mysql> EXPLAIN SELECT * FROM test ORDER BY textcol; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | test | ALL | NULL   | NULL | NULL | NULL | 4 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
1 row in set (0.00 sec) 

mysql> EXPLAIN SELECT * FROM test ORDER BY id; 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra   | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
| 1 | SIMPLE  | test | ALL | NULL   | NULL | NULL | NULL | 4 | Using filesort | 
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
1 row in set (0.00 sec) 
+0

你是否继续在表中看到很多数据?解释并没有告诉你这个查询总是会做什么,只是这个查询在这个时候会做什么。 – 2012-03-09 21:54:14

+0

我将textcol列的大小更改为10个字节,并插入了30000个新行。 SELECT *中的ORDER BY仍然不使用索引。但是,我只注意到SELECT COUNT(*)语句使用索引。任何想法为什么发生这种情况? – Kowshik 2012-03-09 22:12:53

回答

9

由于它必须加载整个表来回答查询和排序4个元素是便宜的,查询优化器可能只是避免触摸索引。它是否仍然发生在更大的表上?

请注意,varchar(3000)列能够' t是覆盖索引,因为MySQL不会在索引中包含超过varchar的前768个字节。

如果您希望查询只读取索引,那么索引必须包含您在其中的每个列SELECT。在innodb上,一旦你使textcol足够小,它应该开始为你的双列表工作;对MyISAM数据,你需要把自己包含在主键列,就像CREATE INDEX textcolindex ON test (textcol,id);

+0

我将textcol列的大小更改为10个字节,并插入了30000个新行。 SELECT *中的ORDER BY仍然不使用索引。但是,我只注意到SELECT COUNT(*)语句使用索引。任何想法为什么发生这种情况? – Kowshik 2012-03-09 22:14:34

+1

为了说明起见,索引对于MyISAM是1000字节限制,对于InnoDB是767,对于3000 varchar字段来说是很害羞的。实际上,MySQL将使用一个索引前缀,它可以用来帮助查找(例如,WHERE子句),但是它不能用于排序,因为它是不完整的:http://dev.mysql.com/doc/refman /5.0/en/order-by-optimization.html – 2012-03-09 22:22:39

+1

@Khowshik,如果没有“覆盖”索引,MySQL将不得不做30,000次寻找来利用索引。 filesort仍然比30,000个搜索更容易。尝试'选择textcol ORDER BY textcol'。 – 2012-03-09 22:29:04

5

订购一些有用的文章优化:

http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/

http://opsmonkey.blogspot.co.uk/2009/03/mysql-query-optimization-for-order-by.html

在很大程度上讨论,保留下来的varchar到767,并添加一个密钥的订单:

CREATE TABLE test (
id INTEGER NOT NULL AUTO_INCREMENT, 
textcol VARCHAR(767), 
PRIMARY KEY(id), 
KEY orderby (`textcol`) 
); 

为了避免filesorts如果增加额外 'WHERE' 参数,使用多列索引延长 '的OrderBy' 索引关键字:

CREATE TABLE test (
id INTEGER NOT NULL AUTO_INCREMENT, 
tom INT(11) NOT NULL DEFAULT 0, 
gerry INT(11) NOT NULL DEFAULT 0, 
textcol VARCHAR(767), 
PRIMARY KEY(id), 
KEY orderby (`tom`,`gerry`, `textcol`) 
); 

另外:

INSERT INTO test (tom, gerry, textcol) VALUES (1,2,'test4'); 
INSERT INTO test (tom, gerry, textcol) VALUES (1,2,'test2'); 
EXPLAIN SELECT id, textcol FROM test WHERE tom = 1 AND gerry =2 ORDER BY textcol; 

额外:“使用其中;使用索引'

+0

感谢您的链接。虽然很老,但他们很有帮助 – 2017-01-12 09:26:55

1

我得到了同样的问题。 MySQL是愚蠢的。 fyi:我有一张拥有5亿多记录的桌子。我想:

select * from table order by tid limit 10000000, 10; 

tid是表中的主键,并自动地被mysql索引。

这花了很长时间,我取消了查询。那么我让MySQL“解释”查询并认识到它不会使用主键的索引。在阅读了许多从MySQL的文档后,我试图强制MySQL通过“USE INDEX(...)”使用索引,DIS也没有工作。然后我认识到,mysql似乎总是将where子句与order by子句关联起来。所以我试图用触及索引的条件来扩展where子句。我结束了:

select * from table use index (PRIMARY) where tid > 0 order by tid limit 10000000, 10; 

其中TID是在表的主键并且是从1开始

这个工作后,我让MySQL的解释查询到我的自动增量值。注意:查询只需要4秒钟。

+0

谢谢你发布这个。这可能有一天会派上用场 – 2017-01-05 15:38:15