如何最佳化sql中的orderBy語句?以下這篇文章為大家介紹一下優化sql中orderBy語句的方法,具有很好的參考價值,希望對大家有幫助。
在使用資料庫進行資料查詢時,難免會遇到基於某些欄位對查詢的結果集進行排序的需求。在sql中通常使用orderby語句來實作。將需要排序的欄位放到 該關鍵字後,如果有多個欄位的話,就用","分割。
select * from table t order by t.column1,t.column2;
上面的sql表示查詢表table中數據,然後先按照column1排序,如果column1相同的話,在按照column2排序,排序的方式默認是降序。當然排序方式也是可以指定的。在被排序欄位後加上 DESC,ASE,分別表示降序和升序。
使用該orderby可以很方便的實作日常的排序操作。使用的多了,不知道你有沒有遇過這種場景:有時候使用orderby後,sql執行效率非常慢,有時候卻比較快,由於整天被curd纏身,也沒有時間研究,反正就是覺得很神奇。趁這個週末比較閒,就來研究下,mysql中orderby是怎麼實現的。
為了方便描述,我們先建立一個資料表t1,如下:
CREATE TABLE `t1` ( `id` int(11) NOT NULL not null auto_increment, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, `c` int(11) DEFAULT NULL, PRIMARY KEY (`id`) , KEY `a` (`a`) USING BTREE ) ENGINE=InnoDB;
並插入資料:
insert into t1 (a,b,c) values (1,1,3); insert into t1 (a,b,c) values (1,4,5); insert into t1 (a,b,c) values (1,3,3); insert into t1 (a,b,c) values (1,3,4); insert into t1 (a,b,c) values (1,2,5); insert into t1 (a,b,c) values (1,3,6);
為了使索引生效,插入10000行7,7, 7,無關數據,數據量少的情況下,會直接全表掃描
insert into t1 (a,b,c) values (7,7,7);
我們現在需要查找a=1的所有記錄,然後按照b字段進行排序。
查詢sql為
select a,b,c from t1 where a = 1 order by b limit 2;
為了防止在查詢過程中全表掃描,我們在欄位a上新增了索引。
首先我們先透過語句
explain select a,b,c from t1 where a = 1 order by b lmit 2;
查看sql的執行計劃,如下所示:
整個sql的執行的過程如下:
1.建立並初始化sort_buffer,並確定需要放到該緩衝區中的字段,也就是a,b ,c這三個字段。 2.從索引樹a中找出第一個滿足a=1的主鍵id,也就是id=1。 3.回表到id索引,取出整行數據,然後從整行數據中,取出a,b,c的值,放入到sort_buffer中。 4.從索引a中依照順序找到下一個a=1的主鍵id。 5.重複步驟3和步驟4,直到取得到最後一個a=1的記錄,也就是主鍵id=5。 6.此時滿足條件a=1的所有記錄的a,b,c字段,全部讀放到了sort_buffer中,然後,對這些數據按照b的值進行排序,排序的方式是快速排序。就是那個面試經常面到的快速排序,時間複雜度為log2n的快速排序。 7.然後從排序後的結果集中取出前2行資料。 上面就是msql中orderby的執行流程。因為放入到sort_buffer中的資料是需要輸出的全部字段,所以這種排序稱為全排序。 看到這裡不知道你是否會有疑問?如果需要排序的資料量很大的話,sort_buffer裝不下怎麼辦? 的確,如果a=1的資料行特別多,且需要存放到sort_buffer中的字段比較多,可能不只a,b,c三個字段,有些業務可能需要輸出更多字段。那麼預設大小只有1M的sort_buffer很可能容納不下。 當sort_buffer容納不下的時候,mysql會建立一批暫時的磁碟檔案來輔助排序。預設會建立12個臨時文件,將需要排序的資料分成12份,每份單獨排序,形成12個內部資料有序的文件,然後把這12個有序文件在合併成一個有序的大文件,最終完成資料的排序。 基於檔案的排序,比起基於記憶體的排序,排序效率低很多,為了提高排序的效率,應該盡量避免基於檔案的排序,要避免基於檔案排序,就需要讓sort_buffer可以容納需要排序的資料量。 所以對於sort_buffer容納不下的情況,mysql進行了最佳化。就是在排序時候,降低存放到sort_buffer中的字段數。 具體優化方式,就是下面的rowId排序RowId 排序
在全字段排序实现中,排序的过程中,要把需要输出的字段全部放到sort_buffer中,当输出的字段比较多的时候,可以放到sort_buffer中的数据行就会变少。也就增大了sort_buffer无法容纳数据的风险,直至出现基于文件的排序。
rowId排序对全字段排序的优化手段,主要是减少了放到sort_buffer中字段个数。
在rowId排序中,只会将需要排序的字段和主键Id放到sort_buffer中。
select a,b,c from t1 where a = 1 order by b limit 2;
在rowId的排序中的执行流程如下:
1.初始化并创建sort_buffer,并确认要放入的的字段,id和b。
2.从索引树a中找到第一个满足a=1的主键id,也就是id=1。
3.回表主键索引id,取出整行数据,从整行数据中取出id和b,存入sort_buffer中。
4.从索引a中取出下一条满足a=1的 记录的主键id。
5.重复步骤3和4,直到最后一个满足a=1的主键id,也就是a=6。
6.对sort_buffer中的数据,按照字段b排序。
7.从sort_buffer中的有序数据集中,取出前2个,因为此时取出的数据只有id和b,要想获取a和c字段,需要根据id字段,回表到主键索引中取出整行数据,从整行数据中获取需要的数据。
根据rowId排序的执行步骤,可以发现:相比全字段排序,rowId排序的实现方式,减少了存放到sort_buffer中的数据量,降低了基于文件的外部排序的可能性。
那rowid排序有不足的地方吗?肯定有的,要不然全字段排序就没有存在的意义了。rowid排序不足之处在于,在最后的步骤7中,增加了回表的次数,不过这个回表的次数,取决于limit后的值,如果返回的结果集比较小的话,回表的次数还是比较小的。
mysql是如何在全字段排序和rowId排序的呢?其实是根据存放的sort_buffer中每行字段的长度决定的,如果mysql认为每次放到sort_buffer中的数据量很大的话,那么就用rowId排序实现,否则使用全字段排序。那么多大算大呢?这个大小的阈值有一个变量的值来决定,这个变量就是 max_length_for_sort_data。如果每次放到sort_buffer中的数据大小大于该字段值的话,就使用rowId排序,否则使用全字段排序。
orderby的优化
上面讲述了orderby的两种排序的方式,以及一些优化策略,优化的目的主要就是避免基于磁盘文件的外部排序。因为基于磁盘文件的排序效率要远低于基于sort_buffer的内存排序。
但是当数据量比较大的时候,即使sort_buffer比较大,所有数据全部放在内存中排序,sql的整体执行效率也不高,因为排序这个操作,本身就是比较消耗性能的。
试想,如果基于索引a获取到所有a=1的数据,按照字段b,天然就是有序的,那么就不用执行排序操作,直接取出来的数据,就是符合结果的数据集,那么sql的执行效率就会大幅度增长。
其实要实现整个sql执行过程中,避免排序操作也不难,只需要创建一个a和b的联合索引即可。
alter table t1 add index a_b (a,b);
添加a和b的联合索引后,sql执行流程就变成了:
1.从索引树(a,b)中找到第一个满足a=1的主键id,也就是id=1。
2.回表到主键索引树,取出整行数据,并从中取出a,b,c,直接作为结果集的一部分返回。
3.从索引树(a,b)上取出下一个满足a=1的主键id。
4.重复步骤2和3,直到找到第二个满足a=1的主键id,并回表获取字段a,b,c。
此时我们可以通过查看sql的执行计划,来判断sql的执行过程中是否执行了排序操作。
explain select a,b from t1 where a = 1 order by b lmit 2;
通过查看执行计划,我们发现extra中已经没有了using filesort了,也就是没有执行排序操作了。
其实还可以通过覆盖索引,对该sql进一步优化,通过在索引中覆盖字段c,来避免回表的操作。
alter table t1 add index a_b_c (a,b,c);
添加索引a_b_c后,sql的执行过程如下:
1.从索引树(a,b,c)中找到第一个满足a=1的索引,从中取出a,b,c。直接作为结果集的一部分直接返回。
2.从索引(a,b,c)中取出下一个,满足a=1的记录作为结果集的一部分。
3.重复执行步骤2,直到查到第二个a=1或者不满足a=1的记录。
此时通过查看执行sql的的还行计划可以发现 extra中只有 Using index。
explain select a,b from t1 where a = 1 order by b lmit 2;
總結
透過對該sql的多次最佳化,sql的最終執行效率和沒有排序的普通sql的查詢效率基本上是一樣的。之所以可以避免orderby的排序操作,就是利用了索引天然有序的特性。
但我們都知道,索引可以加快查詢的效率,但是索引的維護成本比較大,對資料表中資料的新增和修改都會涉及索引的變動,所以索引也不是越多越好,有時候,並不能因為一些不常用的查詢和排序,而增加了過多的索引,得不償失。
【相關推薦:mysql影片教學】
#以上是聊聊優化sql中order By語句的方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

MySQL在數據庫和編程中的地位非常重要,它是一個開源的關係型數據庫管理系統,廣泛應用於各種應用場景。 1)MySQL提供高效的數據存儲、組織和檢索功能,支持Web、移動和企業級系統。 2)它使用客戶端-服務器架構,支持多種存儲引擎和索引優化。 3)基本用法包括創建表和插入數據,高級用法涉及多表JOIN和復雜查詢。 4)常見問題如SQL語法錯誤和性能問題可以通過EXPLAIN命令和慢查詢日誌調試。 5)性能優化方法包括合理使用索引、優化查詢和使用緩存,最佳實踐包括使用事務和PreparedStatemen

MySQL適合小型和大型企業。 1)小型企業可使用MySQL進行基本數據管理,如存儲客戶信息。 2)大型企業可利用MySQL處理海量數據和復雜業務邏輯,優化查詢性能和事務處理。

InnoDB通過Next-KeyLocking機制有效防止幻讀。 1)Next-KeyLocking結合行鎖和間隙鎖,鎖定記錄及其間隙,防止新記錄插入。 2)在實際應用中,通過優化查詢和調整隔離級別,可以減少鎖競爭,提高並發性能。

MySQL不是一門編程語言,但其查詢語言SQL具備編程語言的特性:1.SQL支持條件判斷、循環和變量操作;2.通過存儲過程、觸發器和函數,用戶可以在數據庫中執行複雜邏輯操作。

MySQL是一種開源的關係型數據庫管理系統,主要用於快速、可靠地存儲和檢索數據。其工作原理包括客戶端請求、查詢解析、執行查詢和返回結果。使用示例包括創建表、插入和查詢數據,以及高級功能如JOIN操作。常見錯誤涉及SQL語法、數據類型和權限問題,優化建議包括使用索引、優化查詢和分錶分區。

MySQL是一個開源的關係型數據庫管理系統,適用於數據存儲、管理、查詢和安全。 1.它支持多種操作系統,廣泛應用於Web應用等領域。 2.通過客戶端-服務器架構和不同存儲引擎,MySQL高效處理數據。 3.基本用法包括創建數據庫和表,插入、查詢和更新數據。 4.高級用法涉及復雜查詢和存儲過程。 5.常見錯誤可通過EXPLAIN語句調試。 6.性能優化包括合理使用索引和優化查詢語句。

選擇MySQL的原因是其性能、可靠性、易用性和社區支持。 1.MySQL提供高效的數據存儲和檢索功能,支持多種數據類型和高級查詢操作。 2.採用客戶端-服務器架構和多種存儲引擎,支持事務和查詢優化。 3.易於使用,支持多種操作系統和編程語言。 4.擁有強大的社區支持,提供豐富的資源和解決方案。

InnoDB的鎖機制包括共享鎖、排他鎖、意向鎖、記錄鎖、間隙鎖和下一個鍵鎖。 1.共享鎖允許事務讀取數據而不阻止其他事務讀取。 2.排他鎖阻止其他事務讀取和修改數據。 3.意向鎖優化鎖效率。 4.記錄鎖鎖定索引記錄。 5.間隙鎖鎖定索引記錄間隙。 6.下一個鍵鎖是記錄鎖和間隙鎖的組合,確保數據一致性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

WebStorm Mac版
好用的JavaScript開發工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。