MySQL没有使用ORDER BY的索引

时间:2012-03-09 21:49:21

标签: mysql sql database indexing

我是一个名为' test'的简单MySQL表。有两列:

  1. 自动递增int列名为' id'
  2. Varchar(3000)专栏名为' textcol'
  3. 我根据' textcol'在表格中创建了一个索引。柱。但是,ORDER BY查询似乎没有使用索引,即在textcol上使用ORDER BY的简单查询上的EXPLAIN语句在其输出的Key列中显示NULL,并且还使用filesort。

    任何有助于对ORDER by query使用索引进行更改的指针对我都有用。

    MySQL版本由" mysql --version'给出命令:

    mysql Ver 14.14使用readline 6.2为debian-linux-gnu(x86_64)分发5.1.58

    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)
    

3 个答案:

答案 0 :(得分:9)

由于必须加载整个表来回答查询并且排序4个元素很便宜,查询优化器可能只是避免触及索引。是否还会在较大的表格中出现?

请注意,varchar(3000)列不能作为覆盖索引,因为MySQL不会包含多于索引中varchar的前768个字节。

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

答案 1 :(得分:5)

关于ORDER BY优化的一些有用的文章:

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;

额外:'使用地点;使用索引'

答案 2 :(得分:3)

我遇到了同样的问题。 MySQL是愚蠢的。 fyi:我有一张超过500,000,000条记录的表格。我想:

@media only screen and (max-width: 767px)
.menu {
    display:block;
    position: absolute;
    z-index: 9999999; /* I gave this value because your menu bar's z-index must be smaller than this. */
    margin-top: 15px;
    margin-left: 15px;
}

tid是表中的主键,并由mysql自动编入索引。

这需要很长时间,我取消了查询。然后我让mysql"解释"查询并确认它不会使用主键的索引。从mysql中读取了很多文档后,我试图通过" USE INDEX(...)"强制mysql使用索引。和dis也没有用。然后我认识到mysql似乎总是将where子句与order by子句相关联。所以我尝试使用触及索引的条件扩展where子句。我最终得到了:

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

其中tid是表中的主键,是一个从1开始的自动增量值。

在我让mysql向我解释查询后,这个工作正常。不料:查询只花了4秒钟。