簡體   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