(六)MySQL如何優化--ORDER BY


---
title: 不懂SQL優化?那你就OUT了(六)

MySQL如何優化--ORDER BY

date: 2018-12-08

categories: 數據庫優化
---



在日常開發中,我們經常會使用 order by 子句對某些數據進行排序處理,那么在mysql中使用order by子句時,我們應該怎樣優化order by 子句后的查詢字段來提高查詢效率和排序速度。

在mysql中使用 order by 進行排序有兩種方式:

1. 掃描有序索引進行排序(推薦)

2. 使用文件進行排序(using filesort:內存/磁盤文件排序獲取結果 )

在InnoDB存儲引擎以B+樹作為索引的底層實現,B+樹的葉子節點存儲着所有數據頁而內部節點不存放數據信息,並且所有葉子節點形成一個(雙向)鏈表。

你可以簡單的理解為:索引是一種特殊的文件,當我們建立索引時,mysql會使用雙向鏈表的方式來事先給數據進行排序。

例如:

CREATE TABLE t_testOrderBy(

userid INT PRIMARY KEY AUTO_INCREMENT, -- 用戶編號

username VARCHAR(25), -- 用戶姓名

userAge INT, -- 用戶年齡

usergender CHAR(3), -- 用戶性別

provice VARCHAR(25), -- 所在省份

city VARCHAR(25), -- 所在城市

address VARCHAR(200) -- 詳細地址
);

測試數據:


INSERT INTO t_testOrderBy VALUES(NULL,'張三',18,'男','四川省','成都市','xxxx路222號');
INSERT INTO t_testOrderBy VALUES(NULL,'李四',20,'女','雲南省','昆明市','xxx北路12號');
INSERT INTO t_testOrderBy VALUES(NULL,'王五',24,'男','貴州省','遵義市','xxxxx路18號');
INSERT INTO t_testOrderBy VALUES(NULL,'趙六',19,'女','四川省','綿陽市','xx路234號');
INSERT INTO t_testOrderBy VALUES(NULL,'孫琦',28,'男','雲南省','玉溪市','xxxx路324號');
INSERT INTO t_testOrderBy VALUES(NULL,'王曉琪',21,'女','雲南省','玉溪市','xxxx路123號');


例如:

圖1:

 

 

從圖1可以看出:

使用userid進行排序時,userid上有主鍵索引,mysql會直接遍歷userid索引的葉子節點鏈表,不需要進行額外的排序操作,這就是用索引掃描來排序。

使用 username 字段上沒有任何索引,此時B+樹結構不存在,mysql就只能先掃表篩選出符合條件的數據,再將篩選結果根據username排序。這個排序過程就是filesort。


### 使用有序索引排序時

sql語句中,where子句和order by 子句都可以使用索引, where子句使用索引避免全表掃描,order by 子句使用索引盡量避開使用文件排序(filesort),以提高查詢效率。

雖然索引能提高查詢效率,但在一條sql里,對於一張表的查詢 一次只能使用一個索引(注:排除發生index merge的可能性),也就是說當where子句與order by 子句使用的索引不一致時,MySQL只能使用其中一個索引(B+樹)。

####order by 可以使用索引

1. 當select的字段包含在索引中時,能利用到索引排序功能,進行覆蓋索引掃描.

例如: 為表中的username添加索引。




 

 

 

可以看出當 select 字段中包含了 userage(未建立索引)時,則不能使用索引。

2.當有聯合索引時,order by 子句使用索引必須遵循索引的最左前綴原則。

例如: 為 省份,城市,詳細地址建立聯合索引

 

 





當不遵循最左前綴原則時,則會使用filesort



3.聯合索引中的一部分做等值查詢 ,另一部分作為排序字段。(當然還是要遵循最左前綴原則)




####order by 不使用索引排序

1.select字段在多個索引中,無法使用索引排序。


 

從上圖中可以看出,username的一個獨立的所以,二而provice是聯合索引,當select字段中有多個索引列時,無法使用索引排序


2.對不同的關鍵字使用ORDER BY:

 

 

3.當有聯合索引時,order by 子句使用索引 不 遵循索引的最左前綴原則,無法使用索引排序


 

4. 升降序不一致,無法使用索引排序。

 




5.order by 的字段使用函數

6.返回數據量過大也會不使用索引。

## 使用文件進行排序(后面在介紹)

對於不能利用索引避免排序的sql,數據庫不得不自己實現排序功能以滿足用戶需求,此時sql的執行計划中會出現“Using filesort”,這里需要注意的是filesort並不意味着就是文件排序,其實也有可能是內存排序,這個主要由sort_buffer_size參數與結果集大小確定。


如果排序不可避免,可以用下面的辦法加速:

1. 避免使用 “select * ” 。

2. 增加sort_buffer_size變量的大小。

3. 增加read_rnd_buffer_size變量的大小。

4. 更改tmpdir指向具有大量空閑空間的專用文件系統。

5. 使用合適的列大小存儲具體的內容,比如對於city字段 varchar(25)比varchar(200)能獲取更好的性能.


##order by 總結


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM