![](/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.