简体   繁体   English

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

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

Assume in tableX we have id (primary key) name and age , phone , all with indices.假设在tableX中我们有id (主键) nameagephone ,都有索引。

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

I guess the process is我猜过程是

  1. Using name index to get ids that match Dennis .使用name索引获取与Dennis匹配的 ID。 Denote the id set by S表示S设置的id

  2. Use age index to do order by on the ids obtained in 1, get a sorted id list, denoted by Lage索引对1中得到的ids做order by,得到一个排序好的id列表,记为L

  3. Use the sorted id list L to get phone使用排序后的 id 列表L获取phone

I assume in step 2 it may use a sequential scan along the B+ tree leaf nodes, checking whether the id in that leaf node is in the id set S obtained in step 1. If so, add it into list L , then we can get a id list L sorted by age .我假设在步骤 2 中它可能使用沿 B+ 树叶节点的顺序扫描,检查该叶节点中的 id 是否在步骤 1 中获得的 id 集合S中。如果是,将其添加到列表L中,然后我们可以得到按age排序的 id 列表L

But how is that better than simple sequential scan?但这比简单的顺序扫描好在哪里呢? Aren't they both sequential scan?他们不是都是顺序扫描吗?


Edit:编辑:

explain says it uses index name and does a filesort 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 |
+----+-------------+--------+------------+------+---------------+----------+---------+-------+------+----------+----------------+

Actually I was not sure in what situation index can be useful in order by clause, so I came up with a bad example to illustrate my doubt.实际上我不确定索引在什么情况下可以用于order by子句,所以我想出了一个不好的例子来说明我的疑问。

But the example provided by Tim Biegeleisen is great.但是 Tim Biegeleisen 提供的示例非常棒。


(More table details if you are interested:) (如果您有兴趣,请查看更多表格详情:)

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  |
+----+--------+------+-------+

Actually, the index which should help here is a compound one:实际上,应该在这里提供帮助的索引是一个复合索引:

CREATE INDEX idx ON tableX (name, age, phone)

The above index, if used, would likely have the following steps:如果使用上述索引,可能会有以下步骤:

  • The B-tree can be seeked searching for Dennis name records.可以通过搜索丹尼斯姓名记录来查找 B 树。
  • Once that region of the B-tree is located, the records will then be sorted by age一旦找到 B 树的那个区域,记录就会按年龄排序
  • A scan can be performed to fill the result set with Dennis records, sorted by age可以执行扫描以使用 Dennis 记录填充结果集,按年龄排序
  • The index also includes the phone column making this a covering index for the query;该索引还包括phone列,使其成为查询的覆盖索引 all the columns it needs can be read directly from the index.它需要的所有列都可以直接从索引中读取。

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

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