MyBatis Plus SQL性能分析:從日志到優化的全流程實戰指南

引言

在Java開發的江湖里,MyBatis Plus(MP)早已是“效率利器”——它用極簡的API封裝了CRUD操作,讓開發者從重復的SQL編寫中解放出來。但隨著項目數據量從“萬級”躍升至“十萬級”“百萬級”,一個尷尬的現實逐漸浮現:曾經跑得飛快的MP應用,開始頻繁出現接口超時、數據庫壓力驟增的情況。問題根源往往不在MP本身,而在那些“隱形的SQL”——它們可能因索引缺失、查詢冗余或分頁邏輯欠妥,在數據洪流中淪為性能瓶頸。今天,我們就來聊聊如何用MP的特性,精準定位并解決這些SQL性能問題。


一、定位性能問題:先學會“看日志”和“讀執行計劃”

很多同學遇到慢查詢第一反應是“是不是MP的問題?”——其實MP本身只是ORM框架,SQL性能的核心還是在數據庫本身的執行效率。所以第一步,得先搞清楚“MP到底生成了什么SQL?執行了多久?”

1. 開啟MP的SQL日志:讓“隱形SQL”現形

MP的日志配置非常簡單,但90%的新手可能沒配置對。在application.yml里加上這幾行,開發環境直接能看到完整的SQL執行過程:

mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 控制臺打印SQL(開發環境必備)global-config:db-config:logic-delete-field: logic_delete_field # 邏輯刪除字段(自動過濾已刪數據,避免全表掃描)

輸出示例
控制臺會打印類似這樣的信息:

==>  Preparing: SELECT id,name,age FROM user WHERE age > ? AND logic_delete_field = 0  
==> Parameters: 18(Integer)  
<==      Total: 10  

重點關注Preparing里的SQL語句和Parameters里的參數,這是后續分析的基礎。

2. 數據庫層面:用EXPLAIN“解剖”SQL

光看MP日志還不夠,必須結合數據庫的執行計劃。以MySQL為例,拿到MP生成的SQL后,在Navicat或命令行執行EXPLAIN + SQL語句,重點關注4個指標:

指標含義優化目標
type訪問類型(性能從好到差:system > const > eq_ref > ref > range > index > ALL)至少達到range,避免ALL(全表掃描)
key實際使用的索引不為NULL(未命中索引)
rowsMySQL估計要掃描的行數數值越小越好
Extra額外信息(如Using filesort文件排序、Using temporary臨時表)避免這兩種情況

舉個栗子
假設MP生成了SELECT * FROM user WHERE username LIKE '%張三%',執行EXPLAIN后發現type=ALLkey=NULL,這說明:

  • 沒有給username字段加索引(左模糊LIKE '%xxx'無法用普通索引);
  • 全表掃描導致性能極差(數據量10萬時,掃描時間可能飆升到秒級)。

3. 慢查詢日志:抓出“隱形殺手”

除了實時日志,一定要開啟數據庫的慢查詢日志,記錄執行時間超過閾值的SQL。以MySQL為例,在my.cnf里配置:

slow_query_log = 1                  # 開啟慢查詢
slow_query_log_file = /var/log/mysql/slow.log  # 日志路徑
long_query_time = 1                 # 超過1秒的SQL記錄
log_queries_not_using_indexes = 1   # 記錄未使用索引的SQL(關鍵!)

重啟MySQL后,所有“慢SQL”都會被記錄下來,結合MP日志的時間戳,就能精準定位到具體是哪個業務接口觸發了問題SQL。


二、MP常見的5大SQL性能“坑”

通過日志和執行計劃分析后,你會發現MP的性能問題大多源于使用不當,而不是框架本身的bug。以下是最常見的5類問題,看看你中過幾個?

1. 全表掃描:索引白加了?

典型場景

  • 對高頻查詢字段(如agecreate_time)未加索引;
  • LIKE '%關鍵詞%'做模糊查詢(左模糊無法用普通索引);
  • 邏輯刪除未生效(未配置@TableLogic,導致查詢時仍然掃描已刪除數據)。

優化建議

  • 對高頻查詢、排序、分組的字段(如create_timestatus)添加索引;
  • 左模糊查詢(LIKE '%xxx')盡量改用全文索引(MySQL 5.6+支持FULLTEXT)或搜索引擎(如Elasticsearch);
  • 配置@TableLogic標記邏輯刪除字段,MP會自動過濾已刪數據,避免全表掃描。

2. N+1查詢:循環調用數據庫,能不慢嗎?

典型場景
查詢主表(如用戶表)后,循環調用接口查詢關聯表(如訂單表):

// 錯誤示范:1次查用戶,N次查訂單(總查詢次數=1+N)
List<User> users = userMapper.selectList(wrapper);
users.forEach(user -> {List<Order> orders = orderMapper.selectByUserId(user.getId()); // 循環調用
});

問題
數據量1000時,總查詢次數是1001次!數據庫連接池被占滿,響應時間飆升。

優化方案

  • 批量查詢:先查所有用戶ID,再用selectBatchIds一次性查訂單:
    List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
    List<Order> orders = orderMapper.selectBatchIds(userIds); // 1次查詢搞定
    
  • 懶加載:用@TableField(select = false)標記不需要立即查詢的關聯字段,需要時手動調用;
  • MyBatis二級緩存:對高頻讀、低頻寫的數據(如字典表)啟用緩存(需注意緩存一致性)。

3. 批量操作:舊版本MP的“隱形殺手”

典型場景
saveBatch插入1萬條數據,發現耗時5秒+。查日志發現MP生成了1萬條INSERT語句!

原因
MP 3.5.0之前,默認的批量插入實現是通過foreach拼接多條INSERT語句(非數據庫原生的批量插入),網絡IO和事務提交次數暴增。

優化方案

  • 升級MP到3.5.0+:默認支持INSERT INTO user (name,age) VALUES (a),(b),(c)的原生批量插入;
  • 手動分批處理:數據量極大時(如10萬條),按每1000條分批插入:
    List<List<User>> batches = ListUtils.partition(userList, 1000); // 每批1000條
    batches.forEach(batch -> userMapper.saveBatch(batch));
    

4. 分頁查詢:LIMIT 100000,20 等于“自殺”

典型場景
做后臺管理系統時,用戶翻到第100頁,SQL是SELECT * FROM user LIMIT 100000,20。數據庫需要掃描前100020行,耗時隨數據量線性增長。

問題
LIMIT offset, size的本質是“先掃描offset+size行,再丟棄前offset行”,數據量大時效率極低。

優化方案

  • 小數據量分頁:直接用MP的Page對象,底層會自動處理;
  • 大數據量分頁:改用WHERE id > lastId LIMIT size(需主鍵有序):
    // 假設上一頁最后一條記錄的ID是lastId
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.gt("id", lastId).last("LIMIT 20"); // 直接拼接LIMIT語句
    IPage<User> page = userMapper.selectPage(new Page<>(current, size), wrapper);
    

5. 冗余查詢:SELECT * 害人不淺

典型場景
userMapper.selectById(1L)查詢用戶,但表里有avatar(大圖片)、remark(長文本)等字段,結果返回了幾十KB的數據,內存和網絡都被占滿。

問題
SELECT *會查詢所有字段,包括大字段和不必要的字段,增加網絡傳輸和內存消耗。

優化方案

  • 指定查詢字段:用QueryWrapper.select()明確需要的字段:
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.select("id", "name", "age"); // 只查這三個字段
    User user = userMapper.selectOne(wrapper);
    
  • DTO投影:定義只包含需要字段的DTO類,避免實體類膨脹:
    @Data
    public class UserDTO {private Long id;private String name;private Integer age;
    }
    // 查詢結果直接映射到DTO
    List<UserDTO> dtos = userMapper.selectList(wrapper);
    

三、總結:MP性能優化的“三板斧”

通過上面的案例,我們可以總結出MP SQL性能優化的核心思路:

1. 日志是“眼睛”,EXPLAIN是“放大鏡”

開啟MP日志,結合EXPLAIN分析執行計劃,90%的性能問題都能定位到索引或SQL寫法上。

2. 索引不是萬能的,但不加索引是萬萬不能

高頻查詢字段一定要加索引,左模糊、全表掃描這類“坑”能避則避。

3. 批量和分頁要“講究”

批量操作用3.5.0+的新特性,分頁大數據量時用主鍵范圍查詢,避免LIMIT offset, size

最后想和大家說:MP是工具,SQL性能的核心還是在開發者對業務的理解和數據庫的掌握。多動手分析日志、執行計劃,多測試不同場景下的性能表現,才能讓項目“快人一步”!

你在開發中遇到過哪些MP的SQL性能問題?歡迎在評論區分享你的踩坑經歷和解決方案~

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

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

相關文章

備忘錄設計模式

備忘錄模式&#xff08;Memento Pattern&#xff09;是一種行為設計模式&#xff0c;用于捕獲對象的內部狀態并在需要時恢復該狀態&#xff0c;同時不破壞對象的封裝性。它適用于需要實現撤銷/重做、歷史記錄或狀態快照的場景。核心組件Originator&#xff08;原發器&#xff0…

【世紀龍科技】智能網聯汽車環境感知系統教學難題的創新實踐?

在職業院校智能網聯汽車專業教學中&#xff0c;環境感知系統的教學長期面臨三大核心挑戰&#xff1a;設備成本高昂導致實訓資源不足、抽象原理難以直觀呈現、傳統教學模式難以滿足產業需求。如何讓學生在有限的教學條件下&#xff0c;深入理解激光雷達、毫米波雷達等核心部件的…

ES vs Milvus vs PG vector :LLM時代的向量數據庫選型指南

互聯網時代&#xff0c;關系型數據庫為王。相應的&#xff0c;我們的檢索方式也是精確匹配查詢為主——查找特定的用戶ID、商品編號或訂單狀態。但AI時代&#xff0c;語義檢索成為常態&#xff0c;向量數據庫成為搜索推薦系統&#xff0c;大模型RAG落地&#xff0c;自動駕駛數據…

磁盤陣列技術的功能與分類

磁盤陣列技術 磁盤陣列是由多臺磁盤存儲器組成的一個快速、大容量、高可靠的外存子系統。現在常見的磁盤陣列稱為廉價冗余磁盤陣列&#xff08;Redundant Array of Independent Disk,RAID)。目前&#xff0c;常見的 RAID 如下所示。 廉價冗余磁盤陣列 RAID級別 RAID-0是一種不具…

SpringMVC核心注解:@RequestMapping詳解

概述RequestMapping是SpringMVC中最核心的注解之一&#xff0c;用于將HTTP請求映射到MVC和REST控制器的處理方法上。基本功能RequestMapping主要用于&#xff1a;映射URL到控制器類或方法定義請求方法類型&#xff08;GET、POST等&#xff09;定義請求參數、請求頭等條件使用位…

【雜談】硬件工程師怎么用好AI工具做失效分析

最近被派到國外出差了&#xff0c;工作任務比較重&#xff0c;所以更新的頻率比較低。但在出差工作的過程中&#xff0c;我發現在失效分析時&#xff0c;有相當多的時間做的是比較重復的工作。比如失效分析肯定要一些證據如圖片、視頻。當我們做多臺設備的失效分析時&#xff0…

MyBatis詳解以及在IDEA中的開發

MyBatis概述 MyBatis是一個優秀的持久層框架&#xff0c;它支持定制化SQL、存儲過程以及高級映射。MyBatis避免了幾乎所有的JDBC代碼和手動設置參數以及獲取結果集的過程。 核心特點 優勢&#xff1a; SQL語句與Java代碼分離&#xff0c;便于維護支持動態SQL&#xff0c;靈活性…

LangGraph教程6:LangGraph工作流人機交互

文章目錄 Human-in-the-loop(人機交互) interrupt Warning Human-in-the-loop(人機交互) 人機交互(或稱“在循環中”)工作流將人類輸入整合到自動化過程中,在關鍵階段允許決策、驗證或修正。這在基于 LLM 的應用中尤其有用,因為基礎模型可能會產生偶爾的不準確性。在合規、…

Linux部署Milvus數據庫及Attu UI工具完全指南

一、準備工作1.1 環境要求操作系統&#xff1a;Ubuntu 20.04/Debian 11/CentOS 7硬件配置&#xff1a;至少8GB內存&#xff0c;4核CPU&#xff0c;50GB磁盤空間網絡要求&#xff1a;可訪問互聯網&#xff08;用于拉取Docker鏡像&#xff09;1.2 安裝Docker和Docker Compose1.2.…

開疆智能Profinet轉ModbusTCP網關連接康耐視InSight相機案例

相機配置&#xff1a;硬件連接部分可以查詢我的博客&#xff1a;點擊 這里不做說明。在電子表格視圖下&#xff0c;點擊菜單 “傳感器–網絡設置”&#xff1a;選擇工業協議&#xff0c;如圖。保存作業&#xff0c;并按照提示重啟相機。3. 相機的控制/狀態字&#xff1a;上圖中…

BERT技術架構

### **一、整體定位&#xff1a;純編碼器架構**#### **核心設計思想**> **預訓練微調**&#xff1a;> 1. **預訓練**&#xff1a;在海量無標簽文本上學習通用語言規律> 2. **微調**&#xff1a;用少量標注數據適配具體任務&#xff08;如分類/問答&#xff09;> **…

Python+ArcGIS+AI蒸散發與GPP估算|Penman-Monteith模型|FLUXNET數據處理|多源產品融合|專業科研繪圖與可視化等

結合Python編程與ArcGIS工具&#xff0c;通過AI輔助方法實現蒸散發與植被總初級生產力估算。學習國際流行的Penman-Monteith模型&#xff0c;掌握數據獲取、處理、分析和可視化全流程&#xff0c;培養生態水文與雙碳領域的實踐應用能力。通過DeepSeek、豆包等AI工具輔助代碼編寫…

elasticsearch+logstash+kibana+filebeat實現niginx日志收集(未過濾日志內容)

單點部署 環境準備 基于Rocky9虛擬機&#xff0c;內存大小為4G yum -y install lrzsz useradd elkf passwd elkf#密碼隨意su - elk rz 導入包&#xff0c;筆者導使用版本為7.17.8下載地址&#xff1a;https://www.elastic.co/downloads/past-releases/ tar -xf elasticsearch-7…

hadoop 集群問題處理

1.1.JournalNode 的作用在 HDFS HA 配置中&#xff0c;為了實現兩個 NameNode 之間的狀態同步和故障自動切換&#xff0c;Hadoop 使用了一組 JournalNode 來管理共享的編輯日志。具體來說&#xff0c;JournalNode 的主要職責包括&#xff1a;共享編輯日志&#xff1a;JournalNo…

LeetCode--46.全排列

解題思路&#xff1a;1.獲取信息&#xff1a;給定一個不含重復數字的數組&#xff0c;返回所有可能的全排列&#xff0c;可以按任意順序返回提示信息&#xff1a;1 < nums.length < 6-10 < nums[i] < 102.分析題目&#xff1a;要獲取到所有可能的全排列我們每次會從…

云徙科技----一面(全棧開發)

一、公司是做什么業務的&#xff1f;二、介紹一下自己會用的&#xff0c;熟悉的技術棧&#xff1f;三、“在 Spring 應用中&#xff0c;當你發起一個 RESTful API 請求時&#xff08;例如 GET /api/users/1&#xff09;&#xff0c;計算機系統是如何知道這個請求的&#xff1f;…

我是怎么設計一個訂單號生成策略的(庫存系統)

我是怎么設計一個訂單號生成策略的&#xff08;庫存系統&#xff09;一、背景 最近我在做一套自研的庫存管理系統&#xff0c;其中有一個看似簡單、實則很關鍵的功能&#xff1a;訂單號生成策略。 訂單號不僅要全局唯一&#xff0c;還要有一定的可讀性和業務含義&#xff0c;比…

問津集 #1:Rethinking The Compaction Policies in LSM-trees

文章目錄引言正文結束語引言 陪女朋友出門&#xff0c;我大概有兩個小時左右的空閑時間&#xff0c;遂帶上電腦&#xff0c;翻了下論文列表&#xff0c;選擇了這篇文章做一個簡讀。 因為這一年負責時序系統的存儲引擎和計算引擎演進&#xff0c;而Compaction又是串聯讀寫的核心…

數據產品結構:從數據接入到可視化的完整架構指南

在數據驅動決策的時代&#xff0c;一套高效的數據產品結構是企業挖掘數據價值的基礎。無論是巨頭企業自建的完整體系&#xff0c;還是中小企業依賴的第三方工具&#xff0c;其核心邏輯都是實現 “數據從產生到呈現” 的全鏈路管理。本文將拆解數據產品的五層架構&#xff0c;對…

python學智能算法(二十三)|SVM-幾何距離

引言 前序學習文章中&#xff0c;已經探究了電荷超平面的距離計算方法&#xff0c;相關文章為點與超平面的距離。 在這片文章中&#xff0c;我們了解到計算距離的公式&#xff1a; Fmin?i1...myi(w?xib)F\min_{i1...m}y_{i}(w\cdot x_{i}b)Fi1...mmin?yi?(w?xi?b) 計算…