在 Spring Boot 項目中如何使用索引來優化 SQL 查詢?

在 Spring Boot 項目中使用索引來優化 SQL 查詢是提升數據庫性能最常用的方法之一。下面是詳細的步驟和實踐指南:

核心目標:讓數據庫能夠通過掃描索引(小范圍、有序的數據結構)快速定位到所需數據行,而不是掃描整個表(大數據量下非常慢)。

1. 理解索引的作用和場景

  • 加速查找: 主要優化 WHERE 子句和 JOIN ON 條件的查找速度。
  • 加速排序: 優化 ORDER BY 子句,避免文件排序 (filesort)。
  • 加速分組: 優化 GROUP BY 子句,幫助快速找到相同分組。
  • 唯一性約束: UNIQUE 索引還能保證數據的唯一性。

2. 識別需要索引的查詢

在開始添加索引之前,先找出哪些查詢是性能瓶頸或者執行頻率高。前面我們也介紹過,有興趣的小伙伴可以去看一下之前的文章,我們在回顧一下:

  • MySQL 慢查詢日志 (Slow Query Log): 定位執行時間長的 SQL。
  • APM 工具 (如 SkyWalking): 查看請求中耗時長的調用。
  • EXPLAIN 分析: 對懷疑有問題的 SQL 執行 EXPLAIN,檢查執行計劃。
  • 業務分析: 思考核心業務流程和高頻查詢場景。

重點關注涉及以下操作的查詢:

  • 過濾 (WHERE): findByEmail(String email), findAllByStatus(OrderStatus status)
  • 連接 (JOIN): 加載關聯實體,如查詢訂單及其用戶信息。
  • 排序 (ORDER BY): findAllByOrderByCreatedAtDesc()
  • 分組 (GROUP BY): 統計類查詢。

3. 掌握關鍵的索引類型

  • 單列索引 (Single-Column Index): 對單個列創建索引。適用于簡單的、基于該列的精確匹配或范圍查詢。
    CREATE INDEX idx_users_email ON users (email);
    
  • 聯合索引 / 復合索引 (Composite / Multi-Column Index): 對多個列組合創建索引。極其重要,適用于涉及多個條件的 WHERE 子句或同時需要滿足 WHEREORDER BY / GROUP BY 的查詢。
    -- 適用于 WHERE status = ? AND created_at > ?
    CREATE INDEX idx_orders_status_created ON orders (status, created_at);
    
    • 最左前綴原則 (Leftmost Prefix Rule): 聯合索引 (a, b, c) 可以支持 WHERE a=?WHERE a=? AND b=?WHERE a=? AND b=? AND c=? 的查詢,但通常不支持 WHERE b=?WHERE a=? AND c=?列的順序至關重要。
  • 覆蓋索引 (Covering Index): 如果一個索引包含了查詢所需的所有列(SELECT, WHERE, ORDER BY 等),數據庫可以直接從索引返回結果,無需訪問數據表(回表),性能極高。
    -- 查詢: SELECT user_id, status FROM orders WHERE order_date > ?
    -- 覆蓋索引:
    CREATE INDEX idx_orders_date_user_status ON orders (order_date, user_id, status);
    
  • 唯一索引 (Unique Index): 保證索引列的值唯一,通常用于業務上的唯一標識(如用戶郵箱、手機號),同時也具備普通索引的查詢加速功能。
    CREATE UNIQUE INDEX uk_users_email ON users (email);
    
  • 全文索引 (Full-Text Index): 用于對 TEXT 類型數據進行關鍵詞搜索。

4. 在 Spring Boot 項目中創建和管理索引

下面我們將理論應用到項目中實踐:

  • 錯誤的方式(嚴禁用于生產環境!):

    • 依賴 JPA/Hibernate 的 spring.jpa.hibernate.ddl-auto=updatecreate
    • 原因:
      • update 行為不可預測,可能丟失數據或產生意想不到的變更。
      • create 會刪除整個數據庫!
      • 無法進行版本控制和團隊協作。
      • 繞過了必要的 Code Review 和數據庫變更管理流程。
    • @Table(indexes = ...)@Index 注解:這些注解主要是給 ddl-auto 用的,或者用于生成 DDL 腳本供其他工具使用,不應該直接依賴它們在生產環境自動創建/更新索引
  • 正確的方式(生產環境標準):

    • 使用數據庫遷移工具 (Database Migration Tools): FlywayLiquibase 是 Spring Boot 項目的最佳實踐和必備工具
    • 工作流程:
      1. 添加依賴:pom.xmlbuild.gradle 中添加 Flyway 或 Liquibase 的 Spring Boot Starter 依賴。
        <!-- Flyway Example -->
        <dependency><groupId>org.flywaydb</groupId><artifactId>flyway-core</artifactId>
        </dependency>
        <dependency> <!-- If using MySQL --><groupId>org.flywaydb</groupId><artifactId>flyway-mysql</artifactId>
        </dependency><!-- Liquibase Example -->
        <dependency><groupId>org.liquibase</groupId><artifactId>liquibase-core</artifactId>
        </dependency>
        
      2. 創建遷移腳本:src/main/resources/db/migration (Flyway 默認) 或指定的路徑 (Liquibase) 下創建 SQL 腳本。腳本命名需符合工具的版本規范(例如 Flyway: V1__Initial_schema.sql, V2__Add_index_on_users_email.sql)。
      3. 編寫 DDL: 在 SQL 腳本中使用標準的 CREATE INDEX 語句來定義索引。
        -- V2__Add_index_on_users_email.sql
        CREATE INDEX idx_users_email ON users (email);-- V3__Add_composite_index_on_orders.sql
        CREATE INDEX idx_orders_user_status ON orders (user_id, status);-- V4__Add_unique_index_on_products.sql
        CREATE UNIQUE INDEX uk_products_sku ON products (sku);
        
      4. 運行應用: Spring Boot 應用啟動時,Flyway/Liquibase 會自動檢測并按版本順序執行新的遷移腳本,將索引變更應用到數據庫。
    • 優點:
      • 版本控制: 索引的變更可以像代碼一樣納入 我們Git 管理倉庫中。
      • 可重復: 在任何環境都能應用相同的變更。
      • 自動化: 方便集成到 CI/CD 流程中。
      • 團隊協作: 清晰的記錄了 Schema 的變更歷史。
      • 安全: 變更經過了腳本和版本控制,減少了手動操作的失誤。

5. 針對常見 Spring Boot 查詢場景的索引策略示例

  • 場景:通過唯一業務標識查找實體 (如 User findByEmail(String email);)

    • SQL : SELECT * FROM users WHERE email = ?
    • 索引策略:email 列上創建唯一索引 (Unique Index)
      CREATE UNIQUE INDEX uk_users_email ON users (email);
      
  • 場景:根據狀態過濾并按時間排序的分頁列表 (如 Page<Order> findByStatusOrderByCreatedAtDesc(OrderStatus status, Pageable pageable);)

    • SQL : SELECT * FROM orders WHERE status = ? ORDER BY created_at DESC LIMIT ?, ?
    • 索引策略: 創建聯合索引,包含 statuscreated_atstatus 是等值過濾,放前面;created_at 是排序,放后面。
      CREATE INDEX idx_orders_status_created ON orders (status, created_at);
      
    • 進階 (覆蓋索引): 如果只需要少數幾列(如 id, order_no, status, created_at),可以創建覆蓋索引以避免回表:
      CREATE INDEX idx_orders_status_created_cover ON orders (status, created_at, id, order_no);
      
  • 場景:加載關聯實體 (如獲取訂單及其用戶信息 Order order = orderRepository.findById(id); User user = order.getUser();)

    • JPA 可能生成 (取決于 FetchType):
      • 一次性 JOIN: SELECT ... FROM orders o LEFT JOIN users u ON o.user_id = u.id WHERE o.id = ?
      • N+1 (如果 LAZY Fetching 且后續訪問 user): 先查 order,再根據 order.user_id 查 user。
    • 索引策略: 必須在外鍵列 (orders.user_id) 上創建索引。
      CREATE INDEX idx_orders_user_id ON orders (user_id);
      
      這樣無論是 JOIN 查詢還是 N+1 中的第二次查詢,都能快速通過 user_id 找到對應的訂單或用戶。
  • 場景:多條件過濾查詢 (如 List<Product> findByNameContainingAndCategoryAndPriceBetween(String name, String category, BigDecimal minPrice, BigDecimal maxPrice);)

    • SQL : SELECT * FROM products WHERE category = ? AND price BETWEEN ? AND ? AND name LIKE ? (注意 LIKE 的用法會影響索引效率)
    • 索引策略: 創建聯合索引。通常將等值查詢、選擇性高的列放在前面。范圍查詢 (BETWEEN) 和 LIKE 放后面。
      • 索引:(category, price, name)。這樣可以先用 category 過濾,再用 price 進行范圍掃描。name 上的 LIKE 如果是 '%keyword%' 則此索引無效;如果是 'prefix%' 則可能有部分效果。
      • 如果 name 的查詢更頻繁或選擇性更高,也可以考慮 (name, category, price) 并使用前綴索引。需要根據實際情況分析。
      CREATE INDEX idx_products_category_price_name ON products (category, price, name);
      -- 或者,如果 name 需要前綴索引
      -- CREATE INDEX idx_products_category_price_name ON products (category, price, name(20));
      

6. 驗證索引效果

添加索引后,必須驗證它是否被正確使用且有效:

  • 使用 EXPLAIN:
    • 獲取 Spring Boot 應用生成的 SQL。
    • 用實際參數替換占位符。
    • 在 MySQL 客戶端執行 EXPLAIN [your SQL query];
    • 檢查輸出:
      • key 列是否顯示了你期望使用的索引名?
      • type 列是否是較優的類型(如 ref, range, eq_ref),避免 ALL
      • rows 列估計掃描的行數是否顯著減少?
      • Extra 列是否有 Using filesortUsing temporary?是否出現了 Using index(覆蓋索引)?
  • 性能測試:
    • 在測試環境模擬負載,對比添加索引前后的查詢響應時間。
  • 監控:
    • 觀察 APM 工具中對應數據庫調用的耗時變化。
    • 觀察慢查詢日志中,之前的慢 SQL 是否消失或頻率降低。

總結:

在 Spring Boot 項目中優化 SQL 查詢性能,使用索引是關鍵。核心步驟包括:識別慢查詢 -> 理解查詢模式 -> 選擇合適的索引類型(單列、聯合、覆蓋等) -> 使用數據庫遷移工具 (Flyway/Liquibase) 在版本化的 SQL 腳本中創建索引 -> 使用 EXPLAIN 和監控驗證效果。

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

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

相關文章

Vue3生產環境與Vue Devtools

在 Vue 3 的生產環境中&#xff0c;默認情況下 Vue Devtools 是無法正常使用 的&#xff0c;但開發者可以通過配置強制啟用。以下是關鍵信息總結&#xff1a; &#x1f4cc; 核心結論 默認不可用 Vue 3 生產構建會移除 Devtools 支持以優化性能和安全性。 可強制啟用 通過構建…

ARP滲透學習1

ARP協議工作原理 1. 什么是ARP ARP定義: 地址解析協議&#xff08;Address Resolution Protocol&#xff09;&#xff0c;是根據IP地址獲取物理地址的一個TCP/IP協議。 2. 工作原理 ARP表: 每臺計算機都需要一個ARP表&#xff0c;用來保存IP地址和MAC地址的映射關系。查詢過…

甲骨文云2025深度解析:AI驅動的云原生生態與全球化突圍

一、戰略轉型&#xff1a;從數據庫巨頭到AI云服務先鋒 1. 技術重心向AI與云深度遷移 甲骨文在2025年加速向AI原生云架構轉型&#xff0c;其核心戰略圍繞生成式AI與量子計算展開。通過推出Oracle 23ai自治數據庫&#xff0c;深度集成AI向量搜索功能&#xff0c;并重構云基礎設…

【網絡原理】TCP異常處理(二):連接異常

目錄 一. 由進程崩潰引起的連接斷開 二. 由關機引起的連接斷開 三. 由斷電引起的連接斷開 四. 由網線斷開引起的連接斷開 一. 由進程崩潰引起的連接斷開 在一般情況下&#xff0c;進程無論是正常結束&#xff0c;還是異常崩潰&#xff0c;都會觸發回收文件資源&#xff0c;…

想做博聞強記的自己

2025年4月29日&#xff0c;13~25℃&#xff0c;還好 待辦&#xff1a; 冶金《物理》期末測試 閱卷&#xff08;冶金《物理》期末測試試卷&#xff09; 重修《物理》《物理2》電子材料歸檔 規則變更&#xff0c;《高等數學2》期末試卷推倒重來 遇見&#xff1a;直播畫面。 感受…

IP屬地是實時位置還是自己設置

刷微博、抖音時&#xff0c;評論區總能看到“IP屬地”&#xff1f;這個突然冒出來的小標簽&#xff0c;讓不少網友摸不著頭腦&#xff1a;?IP屬地是實時位置&#xff0c;還是可以自己設置&#xff1f;?別急&#xff0c;今天咱們就來聊聊這個話題&#xff01; 1、什么是IP屬地…

水力壓裂多裂縫擴展誘發光纖應變演化試驗研究

1.概述 本文基于OFDR技術的光纖應變監測方法&#xff0c;監測了真三軸條件下人造巖石試樣與頁巖的水力壓裂試驗。結果表明&#xff0c;OFDR技術能以毫米級分辨率實時監測裂縫起裂、擴展及閉合全過程&#xff0c;并建立基于應變演化的裂縫判別準則&#xff0c;為光纖壓裂監測的…

4、RabbitMQ的七種工作模式介紹

目錄 一、Simple(簡單模式) 1.1 概念 1.2 代碼實現 消費者 運行結果 二、Work Queue&#xff08;工作隊列&#xff09; 2.1 概念 1.2 代碼實現 生產者 消費者 運行結果 三、Publish/Subscribe&#xff08;發布/訂閱模式&#xff09; 3.1 概念 3.2 代碼實現 生產者…

厚銅PCB鉆孔工藝全解析:從參數設置到孔壁質量的關鍵控制點

在現代電子設備中&#xff0c;厚銅PCB&#xff08;印刷電路板&#xff09;扮演著至關重要的角色。它們不僅為電子元件提供了支撐&#xff0c;還實現了電路之間的連接。然而&#xff0c;在生產厚銅PCB時&#xff0c;鉆孔是一個關鍵環節。本文將為您介紹厚銅PCB生產中鉆孔的科普知…

缺口拼圖,非線性坐標關聯

繼上一篇文章&#xff0c; 歡迎一起交流探討 https://t.zsxq.com/GEIze

OTA(Over-The-Air)升級

簡介&#xff1a; OTA&#xff08;Over-the-Air&#xff09;是一種通過無線方式進行數據傳輸和更新的技術&#xff0c;通常用于電子設備&#xff08;如智能手機、汽車、物聯網設備等&#xff09;的軟件、固件或配置更新。OTA可以在設備與服務器之間進行遠程傳輸&#xff0c;用戶…

fastapi和flaskapi有什么區別

FastAPI 和 Flask 都是 Python 的 Web 框架&#xff0c;但設計目標和功能特性有顯著差異。以下是它們的核心區別&#xff1a; 1. ?性能與異步支持? ?FastAPI? 基于 ?Starlette?&#xff08;高性能異步框架&#xff09;和 ?Pydantic?&#xff08;數據校驗庫&#xff09;…

RCS認證是什么?RCS認證的好處?RCS認證所需要的資料

1. RCS&#xff08;Recycled Claim Standard&#xff09;認證 定義&#xff1a;由 Textile Exchange&#xff08;紡織品交易所&#xff09; 制定的國際標準&#xff0c;用于驗證產品中回收材料&#xff08;如再生纖維、塑料、金屬等&#xff09;的含量和供應鏈的可追溯性&…

10 基于Gazebo和Rviz實現導航仿真,包括SLAM建圖,地圖服務,機器人定位,路徑規劃

在9中我們已經實現了機器人的模塊仿真&#xff0c;現在要在這個基礎上實現SLAM建圖&#xff0c;地圖服務&#xff0c;機器人定位&#xff0c;路徑規劃 1. 還是在上述機器人的工作空間下&#xff0c;新建功能包&#xff08;nav&#xff09;&#xff0c;導入依賴 gmapping ma…

OpenGL----OpenGL紋理與紋理緩存區

在現代計算機圖形學中,紋理(Texture)是一個至關重要的概念。它不僅可以為幾何體表面添加細節和真實感,還可以用于實現各種復雜的視覺效果和數據處理。在OpenGL中,紋理的應用范圍非常廣泛,從基本的顏色映射到高級的陰影映射、環境映射等。本文將深入探討OpenGL紋理與紋理緩…

Scikit-learn工具介紹與數據集

一、Scikit-learn簡介與安裝 Scikit-learn是Python中最流行的機器學習庫之一&#xff0c;它提供了簡單高效的數據挖掘和數據分析工具。 Python語言機器學習工具 Scikit-learn包括許多智能的機器學習算法的實現 Scikit-learn文檔完善&#xff0c;容易上手&#xff0c;豐富的A…

Byte-Buddy系列 - 第4講 byte-buddy無法讀取到SpringBoot Jar中的類

目錄 一、問題描述二、原因分析三、解決方案1&#xff08;推薦&#xff09;&#xff1a;獲取線程上下文中的類加載器擴展 四、解決方案2&#xff1a;自定義SpringBoot類加載器 一、問題描述 在使用Byte-Buddy中的TypePool對類進行擴展后&#xff0c;在本地開發集成環境&#x…

AutogenStudio使用

官網介紹&#xff1a;https://microsoft.github.io/autogen/stable/ Autogen是什么&#xff1f; AutoGen 是由微軟開發的一個開源框架&#xff0c;旨在通過 多智能體協作&#xff08;Multi-Agent Collaboration&#xff09; 實現復雜的任務自動化。它的核心思想是讓多個 AI 代…

Vue3 Echarts 3D圓形柱狀圖實現教程以及封裝一個可復用的組件

文章目錄 前言一、實現原理二、series ——type: "pictorialBar" 簡介2.1 常用屬性 三、代碼實戰3.1 封裝一個echarts通用組件 echarts.vue3.2 首先實現一個基礎柱狀圖3.3 添加上下2個橢圓面3.4 進階封裝一個可復用的3D圓形柱狀圖組件 總結 前言 在前端開發的數據可視…

yolov8中train、test、val

說明yolov8中train、test、val是什么意思&#xff0c;是什么作用呢&#xff1f;詳細介紹使用yolov8進行實例分割&#xff0c;我應該如何制作我的數據集呢&#xff1f; 1. YOLOv8中的train、val、test是什么意思&#xff1f;作用是什么&#xff1f; 在YOLOv8&#xff08;由Ultr…