深度分頁介紹及優化建議

深度分頁介紹

查詢偏移量過大的場景我們稱為深度分頁,這會導致查詢性能較低,例如:

# MySQL 在無法利用索引的情況下跳過1000000條記錄后,再獲取10條記錄
SELECT * FROM t_order ORDER BY id LIMIT 1000000, 10

深度分頁問題的原因

當查詢偏移量過大時,MySQL 的查詢優化器可能會選擇全表掃描而不是利用索引來優化查詢。這是因為掃描索引和跳過大量記錄可能比直接全表掃描更耗費資源。

不同機器上這個查詢偏移量過大的臨界點可能不同,取決于多個因素,包括硬件配置(如 CPU 性能、磁盤速度)、表的大小、索引的類型和統計信息等。

MySQL 的查詢優化器采用基于成本的策略來選擇最優的查詢執行計劃。它會根據 CPU 和 I/O 的成本來決定是否使用索引掃描或全表掃描。如果優化器認為全表掃描的成本更低,它就會放棄使用索引。不過,即使偏移量很大,如果查詢中使用了覆蓋索引(covering index),MySQL 仍然可能會使用索引,避免回表操作。

深度分析優化建議

這里以 MySQL 數據庫為例介紹一下如何優化深度分頁。

范圍查詢

當可以保證 ID 的連續性時,根據 ID 范圍進行分頁是比較好的解決方案:

# 查詢指定 ID 范圍的數據
SELECT * FROM t_order WHERE id > 100000 AND id <= 100010 ORDER BY id
# 也可以通過記錄上次查詢結果的最后一條記錄的ID進行下一頁的查詢:
SELECT * FROM t_order WHERE id > 100000 LIMIT 10

這種基于 ID 范圍的深度分頁優化方式存在很大限制:

  1. ID 連續性要求高: 實際項目中,數據庫自增 ID 往往因為各種原因(例如刪除數據、事務回滾等)導致 ID 不連續,難以保證連續性。
  2. 排序問題: 如果查詢需要按照其他字段(例如創建時間、更新時間等)排序,而不是按照 ID 排序,那么這種方法就不再適用。
  3. 并發場景: 在高并發場景下,單純依賴記錄上次查詢的最后一條記錄的 ID 進行分頁,容易出現數據重復或遺漏的問題。

子查詢

我們先查詢出 limit 第一個參數對應的主鍵值,再根據這個主鍵值再去過濾并 limit,這樣效率會更快一些。

阿里巴巴《Java 開發手冊》中也有對應的描述:

利用延遲關聯或者子查詢優化超多分頁場景。

# 通過子查詢來獲取 id 的起始值,把 limit 1000000 的條件轉移到子查詢
SELECT * FROM t_order WHERE id >= (SELECT id FROM t_order where id > 1000000 limit 1) LIMIT 10;

工作原理:

  1. 子查詢 (SELECT id FROM t_order where id > 1000000 limit 1) 會利用主鍵索引快速定位到第 1000001 條記錄,并返回其 ID 值。
  2. 主查詢 SELECT * FROM t_order WHERE id >= ... LIMIT 10 將子查詢返回的起始 ID 作為過濾條件,使用 id >= 獲取從該 ID 開始的后續 10 條記錄。

不過,子查詢的結果會產生一張新表,會影響性能,應該盡量避免大量使用子查詢。并且,這種方法只適用于 ID 是正序的。在復雜分頁場景,往往需要通過過濾條件,篩選到符合條件的 ID,此時的 ID 是離散且不連續的。

當然,我們也可以利用子查詢先去獲取目標分頁的 ID 集合,然后再根據 ID 集合獲取內容,但這種寫法非常繁瑣,不如使用 INNER JOIN 延遲關聯。

延遲關聯

延遲關聯與子查詢的優化思路類似,都是通過將 LIMIT 操作轉移到主鍵索引樹上,減少回表次數。相比直接使用子查詢,延遲關聯通過 INNER JOIN 將子查詢結果集成到主查詢中,避免了子查詢可能產生的臨時表。在執行 INNER JOIN 時,MySQL 優化器能夠利用索引進行高效的連接操作(如索引掃描或其他優化策略),因此在深度分頁場景下,性能通常優于直接使用子查詢。

-- 使用 INNER JOIN 進行延遲關聯
SELECT t1.*
FROM t_order t1
INNER JOIN (SELECT id FROM t_order where id > 1000000 LIMIT 10) t2 ON t1.id = t2.id;

工作原理:

  1. 子查詢 (SELECT id FROM t_order where id > 1000000 LIMIT 10) 利用主鍵索引快速定位目標分頁的 10 條記錄的 ID。
  2. 通過 INNER JOIN 將子查詢結果與主表 t_order 關聯,獲取完整的記錄數據。

除了使用 INNER JOIN 之外,還可以使用逗號連接子查詢。

-- 使用逗號進行延遲關聯
SELECT t1.* FROM t_order t1,
(SELECT id FROM t_order where id > 1000000 LIMIT 10) t2
WHERE t1.id = t2.id;

注意: 雖然逗號連接子查詢也能實現類似的效果,但為了代碼可讀性和可維護性,建議使用更規范的 INNER JOIN 語法。

覆蓋索引

索引中已經包含了所有需要獲取的字段的查詢方式稱為覆蓋索引。

覆蓋索引的好處:

  • 避免 InnoDB 表進行索引的二次查詢,也就是回表操作: InnoDB 是以聚集索引的順序來存儲的,對于 InnoDB 來說,二級索引在葉子節點中所保存的是行的主鍵信息,如果是用二級索引查詢數據的話,在查找到相應的鍵值后,還要通過主鍵進行二次查詢才能獲取我們真實所需要的數據。而在覆蓋索引中,二級索引的鍵值中可以獲取所有的數據,避免了對主鍵的二次查詢(回表),減少了 IO 操作,提升了查詢效率。
  • 可以把隨機 IO 變成順序 IO 加快查詢效率: 由于覆蓋索引是按鍵值的順序存儲的,對于 IO 密集型的范圍查找來說,對比隨機從磁盤讀取每一行的數據 IO 要少的多,因此利用覆蓋索引在訪問時也可以把磁盤的隨機讀取的 IO 轉變成索引查找的順序 IO。
# 如果只需要查詢 id, code, type 這三列,可建立 code 和 type 的覆蓋索引
SELECT id, code, type FROM t_order
ORDER BY code
LIMIT 1000000, 10;

??注意:

  • 當查詢的結果集占表的總行數的很大一部分時,MySQL 查詢優化器可能選擇放棄使用索引,自動轉換為全表掃描。
  • 雖然可以使用 FORCE INDEX 強制查詢優化器走索引,但這種方式可能會導致查詢優化器無法選擇更優的執行計劃,效果并不總是理想。

總結

本文總結了幾種常見的深度分頁優化方案:

  1. 范圍查詢: 基于 ID 連續性進行分頁,通過記錄上一頁最后一條記錄的 ID 來獲取下一頁數據。適合 ID 連續且按 ID 查詢的場景,但在 ID 不連續或需要按其他字段排序時存在局限。
  2. 子查詢: 先通過子查詢獲取分頁的起始主鍵值,再根據主鍵進行篩選分頁。利用主鍵索引提高效率,但子查詢會生成臨時表,復雜場景下性能不佳。
  3. 延遲關聯 (INNER JOIN): 使用 INNER JOIN 將分頁操作轉移到主鍵索引上,減少回表次數。相比子查詢,延遲關聯的性能更優,適合大數據量的分頁查詢。
  4. 覆蓋索引: 通過索引直接獲取所需字段,避免回表操作,減少 IO 開銷,適合查詢特定字段的場景。但當結果集較大時,MySQL 可能會選擇全表掃描。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/72653.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/72653.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/72653.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

live555推流服務器異常

1.后端異常信息&#xff1a; MultiFramedRTPSink::afterGettingFrame1(): The input frame data was too large for our buffer size (100176). 48899 bytes of trailing data was dropped! Correct this by increasing "OutPacketBuffer::maxSize" to at least m…

每日OJ_牛客_宵暗的妖怪_DP_C++_Java

目錄 牛客_宵暗的妖怪_DP 題目解析 C代碼 Java代碼 牛客_宵暗的妖怪_DP 宵暗的妖怪 描述&#xff1a; 露米婭作為宵暗的妖怪&#xff0c;非常喜歡吞噬黑暗。這天&#xff0c;她來到了一條路上&#xff0c;準備吞噬這條路上的黑暗。這條道路一共被分為n 部分&…

20250306-筆記-精讀class CVRPEnv:step(self, selected)

文章目錄 前言一、if self.time_step<4:控制時間步的遞增判斷是否在配送中心特定時間步的操作更新更新當前節點和已選擇節點列表更新需求和負載更新訪問標記更新負無窮掩碼更新步驟狀態&#xff0c;將更新后的狀態同步到 self.step_state 二、使用步驟總結 前言 class CVRP…

Flowable 基本入門

flowable.7z官方版下載丨最新版下載丨綠色版下載丨APP下載-123云盤 1、Flowable介紹 Flowable是BPMN的一個基于java的軟件實現&#xff0c;不過Flowable不僅僅包括BPMN&#xff0c;還有DMN決策表和CMMN Case管理引擎&#xff0c;并且有自己的用戶管理、微服務API等一系列功能&a…

完全背包-一維數組

52. 攜帶研究材料&#xff08;第七期模擬筆試&#xff09; 題目描述 小明是一位科學家&#xff0c;他需要參加一場重要的國際科學大會&#xff0c;以展示自己的最新研究成果。他需要帶一些研究材料&#xff0c;但是他的行李箱空間有限。這些研究材料包括實驗設備、文獻資料和…

景聯文科技:以專業標注賦能AI未來,驅動智能時代的精準躍遷

在人工智能技術重塑全球產業格局的今天&#xff0c;高質量訓練數據已成為驅動算法進化的核心燃料。作為數據智能服務領域的領軍者&#xff0c;景聯文科技深耕數據標注行業多年&#xff0c;以全棧式數據解決方案為核心&#xff0c;構建起覆蓋數據采集、清洗、標注、質檢及算法調…

洛谷B2074 計算星期幾

B2074 計算星期幾 - 洛谷 代碼區&#xff1a; #include<algorithm> #include<iostream> #include<unordered_map> #include<string> using namespace std; int main() {unordered_map<int, string> m { { 1,"Monday" },{2,"Tue…

協同過濾推薦算法+微信小程序的農產品團購推薦平臺(程序+論文+講解+安裝+調試+售后)

感興趣的可以先收藏起來&#xff0c;還有大家在畢設選題&#xff0c;項目以及論文編寫等相關問題都可以給我留言咨詢&#xff0c;我會一一回復&#xff0c;希望幫助更多的人。 系統介紹 在當今時代&#xff0c;科學技術正以令人矚目的速度迅猛進步&#xff0c;經濟社會也隨之…

十大經典排序算法簡介

一 概述 本文對十大經典排序算法做簡要的總結(按常用分類方式排列),包含核心思想、時間/空間復雜度及特點。 二、比較類排序 1. 冒泡排序 (BUBBLE SORT) 思想:重復交換相鄰逆序元素,像氣泡上浮 復雜度: 時間:O(n^2)(最好情況O(n)) 空間:O(1) 特點:簡單但效率低,穩…

[自然語言處理]pytorch概述--什么是張量(Tensor)和基本操作

pytorch概述 PyTorch 是?個開源的深度學習框架&#xff0c;由 Facebook 的??智能研究團隊開發和維護&#xff0c;于2017年在GitHub上開源&#xff0c;在學術界和?業界都得到了?泛應? pytorch能做什么 GPU加速自動求導常用網絡層 pytorch基礎 量的概念 標量&#xf…

Spring統一格式返回

目錄 一&#xff1a;統一結果返回 1&#xff1a;統一結果返回寫法 2&#xff1a;String類型報錯問題 解決方法 二&#xff1a;統一異常返回 統一異常返回寫法 三&#xff1a;總結 同志們&#xff0c;今天咱來講一講統一格式返回啊&#xff0c;也是好久沒有講過統一格式返…

【無標題】四色拓撲模型與宇宙歷史重構的猜想框架

### 四色拓撲模型與宇宙歷史重構的猜想框架 --- #### **一、理論基礎&#xff1a;四色拓撲與時空全息原理的融合** 1. **宇宙背景信息的拓撲編碼** - **大尺度結構網絡**&#xff1a;將星系團映射為四色頂點&#xff0c;纖維狀暗物質結構作為邊&#xff0c;構建宇宙尺度…

藍橋杯 封閉圖形個數

藍橋杯 封閉圖形個數 題目 鏈接 解答 # 數字個數 n int(input()) # 數字 ls input().split() # 統計數字的圈數 o_nums {} for i, x in enumerate(ls):o_num 0for c in x:if int(c) in [0, 4, 6, 9]:o_num 1elif c 8:o_num 2o_nums[i] o_num # 字典根據圓圈數排序 …

基于javaweb的SpringBoot學生在線考試管理系統設計和實現(源碼+文檔+部署講解)

技術范圍&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬蟲、數據可視化、小程序、安卓app、大數據、物聯網、機器學習等設計與開發。 主要內容&#xff1a;免費功能設計、開題報告、任務書、中期檢查PPT、系統功能實現、代碼編寫、論文編寫和輔導、論…

國產編輯器EverEdit - 超多樣式設置

1 設置-編輯-樣式 1.1 設置說明 1.1.1 折疊樣式 默認為箭頭&#xff0c;折疊樣式選項如下&#xff1a; 箭頭&#xff1a; 矩形和線條 五邊形 圓形圖標 1.1.2 光標樣式 光標用于指示當前用戶輸入位置&#xff0c;光標樣式選項如下&#xff1a; 默認 纖細 字寬 …

Linux - 線程控制

一、線程概念 1&#xff09;線程地址空間 線程與進程共享相同的虛擬地址空間&#xff0c;因此線程在訪問內存時與進程沒有本質的區別。但線程共享和獨占的內存區域有不同的特點&#xff0c;理解這些特性對于正確使用線程至關重要。 1. 線程地址空間的組成 線程的地址空間是…

通過多線程分別獲取高分辨率和低分辨率的H264碼流

目錄 一.RV1126 VI采集攝像頭數據并同時獲取高分辨率碼流和低分辨率碼流流程 ?編輯 1.1初始化VI模塊&#xff1a; 1.2初始化RGA模塊&#xff1a; 1.3初始化高分辨率VENC編碼器、 低分辨率VENC編碼器&#xff1a; 1.4 VI綁定高分辨率VENC編碼器&#xff0c;VI綁定RGA模塊…

部署RabbitMQ集群詳細教程

部署RabbitMQ集群詳細教程 下面是一份在 Ubuntu 環境下部署 RabbitMQ 集群的詳細步驟說明&#xff0c;涉及主機名設置、Erlang & RabbitMQ 安裝、管理插件啟用、集群通信 Cookie 配置、節點加入集群、鏡像隊列策略設置以及集群驗證等。為了演示方便&#xff0c;以下示例假…

【Linux】之【Bug】VMware 虛擬機開機 一直卡在黑屏左上角下劃線閃爍界面

解決 參考&#xff1a; 解決Ubuntu20.04 開機黑屏光標閃爍進不去系統 Centos根目錄100%解決思路 當前界面 ctrlaltf3-f6 暫時進入終端界面 df -h 查看發現根目錄 磁盤空間已滿 執行命令 查看當前目錄占用內存明細 sudo du -h -x --max-depth1清理無用的大內存文件 或者安裝…

webflux集成langchain4j基礎版

伴隨著大模型應用的興起&#xff0c;webflux逐漸引起關注。為了以java的方式運行AI應用&#xff0c;讓我們一起學習webflux集成langchain4j吧。 1. 項目依賴 首先&#xff0c;你需要在 pom.xml 中添加必要的依賴&#xff1a; <dependencies><!-- Spring WebFlux --…