-
其實,並非全部的`order by`語句,都須要排序操做的。從上面分析的執行過程,咱們能夠看到,MySQL 之因此須要生成臨時表,而且在臨時表上作排序操做,其緣由是**原來的數據都是無序的**。
-
若是可以保證從`city`這個索引上取出來的行,自然就是按照 name 遞增排序的話,是否是就能夠不用再排序了呢?
-
所以想到了聯合索引,建立`(city,name)`聯合索引,sql 語句以下:
alter table user add index city_user(city, name);spa
-
此時的索引樹以下: ![city,name索引樹](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/13/1717385bd1788120~tplv-t2oaga2asx-image.image)
-
在這個索引裏面,咱們依然能夠用樹搜索的方式定位到第一個知足`city='蘇州'`的記錄,而且額外確保了,接下來按順序取「下一條記錄」的遍歷過程當中,只要 city 的值是杭州,name 的值就必定是有序的。
-
按照上圖,整個查詢的流程以下:
-
從索引(city,name)找到第一個知足 city='蘇州’條件的主鍵 id。
-
到主鍵 id 索引取出整行,取 name、city、age 三個字段的值,做爲結果集的一部分直接返回。
-
從索引(city,name)取下一個記錄主鍵 id。
-
重複步驟 二、3,直到查到第 1000 條記錄,或者是不知足 city='蘇州'條件時循環結束。
-
對應的流程圖以下: ![city,name聯合索引的執行流程](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/13/1717385bfa076547~tplv-t2oaga2asx-image.image)
-
能夠看到,這個查詢過程不須要臨時表,也不須要排序。接下來,咱們用 explain 的結果來印證一下。 ![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/13/1717385bfb960b8f~tplv-t2oaga2asx-image.image)
-
從圖中能夠看到,`Extra`字段中沒有`Using filesort`了,也就是不須要排序了。並且因爲`(city,name)`這個聯合索引自己有序,**因此這個查詢也不用把 4000 行全都讀一遍,只要找到知足條件的前 1000 條記錄就能夠退出了**。也就是說,在咱們這個例子裏,只須要掃描 1000 次。
-
難道僅僅這樣就能知足了?此條查詢語句是否能再優化呢? ![](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/13/1717385bff11b6e0~tplv-t2oaga2asx-image.image)
-
朋友們還記得覆蓋索引嗎?覆蓋索引的好處就是可以避免再次回表查詢,不瞭解的朋友們能夠看一下陳某以前寫的文章:[Mysql 性能優化:如何使用覆蓋索引?](https://mp.weixin.qq.com/s/-IRhK4KyDCkTd_lojeEolw)。
-
咱們建立`(city,name,age)`聯合索引,這樣在執行上面的查詢語句就能使用覆蓋索引了,避免了回表查詢了,sql 語句以下:
alter table user add index city_user_age(city, name, age);線程
-
此時執行流程圖以下: ![覆蓋索引使用執行流程](https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2020/4/13/1717385bff36a160~tplv-t2oaga2asx-image.image)
-
**固然,覆蓋索引可以提高效率,可是維護索引也是須要代價的,所以還須要權衡使用。**