为什么s上的索引不用于排序?

时间:2010-03-23 11:06:59

标签: mysql query-optimization

设定:

mysql> create table test(id integer unsigned,s varchar(30));
Query OK, 0 rows affected (0.05 sec)

mysql> insert into test(id,s) value(1,'s');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test(id,s) value(1,'tsr');
Query OK, 1 row affected (0.00 sec)

mysql> insert into test(id,s) value(1,'ts3r');
Query OK, 1 row affected (0.00 sec)

mysql> create index i_test_id on test(id);
Query OK, 3 rows affected (0.08 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> create index i_test_s on test(s);
Query OK, 3 rows affected (0.05 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql>  insert into test(id,s) value(21,'ts3r');
Query OK, 1 row affected (0.00 sec)

然后运行:

mysql> explain select * from test where id in (1) order by s desc;
+----+-------------+-------+------+---------------+-----------+---------+-------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key       | key_len | ref   | rows | Extra                       |
+----+-------------+-------+------+---------------+-----------+---------+-------+------+-----------------------------+
|  1 | SIMPLE      | test  | ref  | i_test_id     | i_test_id | 5       | const |    2 | Using where; Using filesort |
+----+-------------+-------+------+---------------+-----------+---------+-------+------+-----------------------------+
1 row in set (0.02 sec)

我们可以看到它使用filesort而不是使用s上的索引,当选定的结果集很大时,这将很慢。如何优化它?

5 个答案:

答案 0 :(得分:1)

  

有时MySQL不使用索引,即使有索引也是如此。发生这种情况的一种情况是,优化器估计使用索引将需要MySQL访问表中非常大比例的行。

来自:MySQL 5.1 Reference Manual: How MySQL Uses Indexes

答案 1 :(得分:0)

id上的索引用于标识要返回的行。根据您使用的MySQL版本,它可能只允许每个表使用一个索引,并且优化器已经确定使用索引过滤行而不是排序更有效。

答案 2 :(得分:0)

在列'id'上创建聚簇索引。 聚集索引表示物理排序。这样我就猜测在调用此查询时不会有文件排序。

但是一个表只能有一个聚簇索引。因此,如果您有另一列作为表的主键,则可能无法在列'id'上创建聚簇索引。 默认情况下,主键是群集。

答案 3 :(得分:0)

您使用的是哪个版本的MySQL?直到版本5,MySQL才能为每个表使用多个索引。

要使用的索引的选择还取决于结果集的大小。如果结果中只返回了两条记录,则无论如何都不能使用索引。对于这样小的结果集,MySQL似乎并不介意手动排序。

然而,如果这是一个常见的查询,你可以做些什么来真正帮助MySQL,添加一个复合索引('id','s')。基本上,它几乎就像你创建另一个总是按id然后排序的小表,所以不需要filesort,它只需要一个索引,而不是两个索引。

答案 4 :(得分:0)

您遇到的问题来自于您在sql语句中放置Order by子句这一事实。这导致MySql跳过使用任何索引并在S上进行完整排序。解释语句显示MySql有i_test_id可能的索引可供选择,关键字段显示它已被选中,但它必须也对s进行排序。优化器选择不使用i_test_s作为可能的索引,因为它在性能方面会更昂贵。您可以通过以磁盘空间为代价构建componsite索引来解决此问题,或者您可以使用Unions以不同方式构建查询。但是在你的例子中没试过。