设定:
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
上的索引,当选定的结果集很大时,这将很慢。如何优化它?
答案 0 :(得分:1)
有时MySQL不使用索引,即使有索引也是如此。发生这种情况的一种情况是,优化器估计使用索引将需要MySQL访问表中非常大比例的行。
答案 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以不同方式构建查询。但是在你的例子中没试过。