繁体   English   中英

为什么order by子句可以利用索引?

[英]Why order by clause can make use of index?

假设在tableX中我们有id (主键) nameagephone ,都有索引。

在此查询中: select phone from tableX where name='Dennis' order by age

我猜过程是

  1. 使用name索引获取与Dennis匹配的 ID。 表示S设置的id

  2. age索引对1中得到的ids做order by,得到一个排序好的id列表,记为L

  3. 使用排序后的 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)

如果使用上述索引,可能会有以下步骤:

  • 可以通过搜索丹尼斯姓名记录来查找 B 树。
  • 一旦找到 B 树的那个区域,记录就会按年龄排序
  • 可以执行扫描以使用 Dennis 记录填充结果集,按年龄排序
  • 该索引还包括phone列,使其成为查询的覆盖索引 它需要的所有列都可以直接从索引中读取。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM