Mysql索引掃描排序
阿新 • • 發佈:2019-01-28
使用索引掃描來做排序
生成有序結果
Mysql
有兩種操作可以用來生成有序結果:
+ 排序操作: 將查找出來的結果使用排序演算法進行排序
+ 按索引順序掃描: ORDER BY
語句後跟著一個被索引的列,如此一來索引的順序就是索引對應記錄的順序,這樣直接順著索引一直往下讀取記錄即可得到有序的結果。
建立用於排序掃描的索引
按照索引順序掃描的好處是不言而喻的,因為查找出來的結果就是有序結果而無需執行額外的排序操作,這樣執行的速度就會相對較快。但是,不是什麼時候按照索引掃描的執行速都會是最快的。雖然掃描索引的速度是非常快的,但是如果索引不能覆蓋到查詢所需要的所有資料列的話,這種情況下每掃描一個索引就必須相對應地回表一次,這樣的IO幾乎是隨機IO,如此一來雖然索引掃描無需執行一次排序演算法,但是隨機IO操作會大大拖慢執行速度,導致按照索引掃描的執行速度反而要比排序操作要慢。
什麼時候Mysql會使用索引排序?
索引列的順序與
ORDER BY
字句的順序一致時,並且所有列的排列順序一樣。
因為多列索引的索引值是綜合了多個列計算而得的,且計算的結果與列的順序有關。例如下面就是一個例子://虛擬碼 index_t hash(string x, string y, string z){ return x.append(y).append(z); }
當執行
ORDER BY x, y, z
時,實際上就是ORDER BY hash(x, y, z)
,這樣必須保證x, y, z
- 當查詢關聯多張表時,則只有當
ORDER BY
中引用的欄位全為第一張表中的欄位,才可能使用索引排序。 - 有一種例外,
ORDER BY
後跟的欄位可以不滿足最左字首原則:當前導量為常量的時候。
幾個例子
- 有一張表
rental
如下所示:
CREATE TABLE rental{
...
PRIMARY KEY(rental_id),
UNIQUE KEY rental_date(rental_date, inventory_id, customer_id),
KEY idx_fk_inventory_id(inventory_id),
KEY idx_fk_customer_id(customer_id),
KEY idx_fk_staff_id(staff_id),
...
};
執行語句:
EXPLAIN SELECT rental_id, staff_id FROM sakila.rental
-> WHERE rental_date = '2005-05-5'
-> ORDER BY inventory_id, customer_id\G
輸出為:
possible_keys: rental_date
key: rental_date
rows: 1
extra: using where
這裡看到extra: using where
而不是extra: using filesort
表明此次查詢並沒有排序操作,而是直接通過掃描索引獲得有序結果。因為這在這裡,雖然ORDER BY
語句的欄位並沒有滿足最左字首的原則,但是由於前導列只定了一個常量,所以可以使用索引掃描進行排序。
- 將上述查詢改為以下語句也沒問題:
EXPLAIN SELECT rental_id, staff_id FROM sakila.rental
-> WHERE rental_date > '2005-05-5'
-> ORDER BY rental_date, inventory_id, customer_id\G
因為這裡雖然沒有將前導列指定為常量,但是這裡ORDER BY
的語句滿足了最左字首原則。
- 下列語句不能使用掃描索引得到有序結果:
...WHERE rental_date > '2005-05-5' ORDER BY rental_date DESC, inventory_id ASC
因為排序方向不一致。...WHERE rental_date = '2005-05-5' ORDER BY rental_date , staff_id
因為使用了一個不在索引中的列。...WHERE rental_date > '2005-05-5' ORDER BY inventory_id
因為不滿足最左字首索引