![](/img/trans.png)
[英]Why does Mysql decide to use an index on column specified in Order By clause when its not present in where clause?
[英]Why order by clause can make use of index?
假设在tableX
中我们有id
(主键) name
和age
, phone
,都有索引。
在此查询中: select phone from tableX where name='Dennis' order by age
我猜过程是
使用name
索引获取与Dennis
匹配的 ID。 表示S
设置的id
用age
索引对1中得到的ids做order by,得到一个排序好的id列表,记为L
使用排序后的 id 列表L
获取phone
我假设在步骤 2 中它可能使用沿 B+ 树叶节点的顺序扫描,检查该叶节点中的 id 是否在步骤 1 中获得的 id 集合S
中。如果是,将其添加到列表L
中,然后我们可以得到按age
排序的 id 列表L
但这比简单的顺序扫描好在哪里呢? 他们不是都是顺序扫描吗?
编辑:
explain
说它使用索引name
并进行filesort
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+
| 1 | SIMPLE | tableX | NULL | ref | idx_name | idx_name | 123 | const | 1 | 100.00 | Using filesort |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+
实际上我不确定索引在什么情况下可以用于order by
子句,所以我想出了一个不好的例子来说明我的疑问。
但是 Tim Biegeleisen 提供的示例非常棒。
(如果您有兴趣,请查看更多表格详情:)
mysql> create table tableX(
-> id int primary key,
-> name varchar(30),
-> age int,
-> phone varchar(30)
-> );
Query OK, 0 rows affected (0.07 sec)
mysql> create index idx_name on tableX(name);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> create index idx_age on tableX(age);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> create index idx_phone on tableX(phone);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from tableX;
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| tableX | 0 | PRIMARY | 1 | id | A | 1 | NULL | NULL | | BTREE | | | YES | NULL |
| tableX | 1 | idx_name | 1 | name | A | 1 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tableX | 1 | idx_age | 1 | age | A | 1 | NULL | NULL | YES | BTREE | | | YES | NULL |
| tableX | 1 | idx_phone | 1 | phone | A | 1 | NULL | NULL | YES | BTREE | | | YES | NULL |
+--------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.01 sec)
mysql> select * from tableX;
+----+--------+------+-------+
| id | name | age | phone |
+----+--------+------+-------+
| 1 | Jack | 20 | 180 |
| 2 | Dennis | 22 | 180 |
| 3 | Dennis | 18 | 1790 |
+----+--------+------+-------+
实际上,应该在这里提供帮助的索引是一个复合索引:
CREATE INDEX idx ON tableX (name, age, phone)
如果使用上述索引,可能会有以下步骤:
phone
列,使其成为查询的覆盖索引; 它需要的所有列都可以直接从索引中读取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.