搜尋
首頁資料庫mysql教程聊聊優化sql中order By語句的方法

如何最佳化sql中的orderBy語句?以下這篇文章為大家介紹一下優化sql中orderBy語句的方法,具有很好的參考價值,希望對大家有幫助。

聊聊優化sql中order By語句的方法

在使用資料庫進行資料查詢時,難免會遇到基於某些欄位對查詢的結果集進行排序的需求。在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的執行計劃,如下所示:

##在extra中我們可以看到出現了Using filesort,這個表示該sql執行過程中,執行了排序操作,排序操作在sort_buffer中完成,sort_buffer是mysql分配給每個線程的一個內存緩衝區,該緩衝區專門用來完成排序,大小默認是1M,其大小由變數sort_buffer_size 進行控制。

mysql在實作orderby時,根據放入到sort_buffer中的欄位內容不同,進行了兩種不同實作方式:全欄位排序和rowid排序。

全字段排序

首先我們先透過一張圖整體看一下sql執行過程:

mysql先根據查詢條件決定需要排序的資料集,也就是表中a=1的資料集,也就是主鍵id從1到6的這些記錄。

整個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中文網其他相關文章!

陳述
本文轉載於:脚本之家。如有侵權,請聯絡admin@php.cn刪除
MySQL的位置:數據庫和編程MySQL的位置:數據庫和編程Apr 13, 2025 am 12:18 AM

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

MySQL:從小型企業到大型企業MySQL:從小型企業到大型企業Apr 13, 2025 am 12:17 AM

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

幻影是什麼讀取的,InnoDB如何阻止它們(下一個鍵鎖定)?幻影是什麼讀取的,InnoDB如何阻止它們(下一個鍵鎖定)?Apr 13, 2025 am 12:16 AM

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

mysql:不是編程語言,而是...mysql:不是編程語言,而是...Apr 13, 2025 am 12:03 AM

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

MySQL:世界上最受歡迎的數據庫的簡介MySQL:世界上最受歡迎的數據庫的簡介Apr 12, 2025 am 12:18 AM

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

MySQL的重要性:數據存儲和管理MySQL的重要性:數據存儲和管理Apr 12, 2025 am 12:18 AM

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

為什麼要使用mysql?利益和優勢為什麼要使用mysql?利益和優勢Apr 12, 2025 am 12:17 AM

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

描述InnoDB鎖定機制(共享鎖,獨家鎖,意向鎖,記錄鎖,間隙鎖,下一鍵鎖)。描述InnoDB鎖定機制(共享鎖,獨家鎖,意向鎖,記錄鎖,間隙鎖,下一鍵鎖)。Apr 12, 2025 am 12:16 AM

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

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

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

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

MantisBT

MantisBT

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