MySQL預(yù)編譯語句過多告警排查及解決方案
業(yè)務(wù)背景
在使用Spring Cloud Alibaba搭建的微服務(wù)架構(gòu)中,項目采用ShardingSphere進行分庫分表,MyBatis-Plus作為持久層。線上環(huán)境突發(fā)大量預(yù)編譯語句過多的數(shù)據(jù)庫告警,導(dǎo)致系統(tǒng)性能下降。
排查過程
1. 初步排查:聯(lián)系云數(shù)據(jù)庫廠商
首先,聯(lián)系云數(shù)據(jù)庫服務(wù)廠商協(xié)助排查,確認(rèn)問題是由于預(yù)編譯緩存未被釋放,導(dǎo)致占用過多數(shù)據(jù)庫資源。
2. 排查連接池配置
懷疑問題與連接池有關(guān),特別是考慮到線上負(fù)載較高的高峰時段。經(jīng)過檢查,項目使用的是HikariCP連接池,相關(guān)配置如下:

特別關(guān)注兩個參數(shù):
maxLifetime: 連接池最大生命周期idleTimeout: 連接池空閑超時時間
在進行斷點調(diào)試后,由于項目使用了Sharding-JDBC,某些參數(shù)并未按照Hikari的默認(rèn)值生效,而是被Sharding進行初始化配置。Sharding的相關(guān)代碼如下:

此時可以初步排除連接池配置問題,因為Sharding已將idleTimeout配置為60秒。
3. 分析HikariCP源碼與Statement Cache問題
深入分析HikariCP源碼,查找與PreparedStatement緩存相關(guān)的內(nèi)容,發(fā)現(xiàn)README.md關(guān)鍵描述:
Statement Cache
HikariCP與其他連接池(如Apache DBCP、Vibur、c3p0等)在處理PreparedStatement緩存時的區(qū)別:
- HikariCP: 不提供
PreparedStatement緩存,原因是連接池層級緩存PreparedStatement只能按連接緩存,導(dǎo)致內(nèi)存占用過大。 - 其他連接池: 許多連接池提供
PreparedStatement緩存,但這會導(dǎo)致大量PreparedStatement對象及相關(guān)執(zhí)行計劃在內(nèi)存中存儲,影響性能。
HikariCP并不緩存PreparedStatement,因為多數(shù)數(shù)據(jù)庫JDBC驅(qū)動已經(jīng)內(nèi)置緩存機制,可以跨連接共享執(zhí)行計劃,避免重復(fù)占用內(nèi)存。
要點:
- 連接池層級的
PreparedStatement緩存問題:在連接池層緩存會導(dǎo)致大量內(nèi)存占用,且不支持跨連接共享。 - 數(shù)據(jù)庫驅(qū)動緩存的優(yōu)勢:數(shù)據(jù)庫驅(qū)動層提供的緩存更高效,能夠共享執(zhí)行計劃,減少內(nèi)存占用。
- 反模式:在連接池層進行緩存
PreparedStatement是性能反模式。
4. MySQL驅(qū)動配置分析
進一步排查MySQL驅(qū)動,發(fā)現(xiàn)項目使用的mysql-connector-j:8.3.0驅(qū)動,關(guān)鍵配置useServerPrepStmts默認(rèn)為true,即開啟服務(wù)端的預(yù)編譯緩存。而在同一項目中,其他服務(wù)使用的是mysql-connector-java:8.0.16,該版本的默認(rèn)配置為false。
核心代碼:

通過對比,確認(rèn)開啟服務(wù)端預(yù)編譯緩存是導(dǎo)致告警的根本原因。
解決方案
通過排查,最終確定問題原因是服務(wù)端的預(yù)編譯緩存未關(guān)閉。由于項目采用分庫分表,并且在同一數(shù)據(jù)庫實例中創(chuàng)建了多個Schema,默認(rèn)開啟的服務(wù)端預(yù)編譯緩存容易導(dǎo)致資源占用過高。
解決步驟:
在JDBC連接字符串中添加配置&useServerPrepStmts=false,關(guān)閉MySQL的服務(wù)端預(yù)編譯緩存。
例如,JDBC連接URL修改如下:
jdbc:mysql://localhost:3306/dbname?useServerPrepStmts=false
配置完成后,重新啟動服務(wù),觀察效果。關(guān)閉服務(wù)端預(yù)編譯緩存后,數(shù)據(jù)庫告警明顯減少,系統(tǒng)性能得到提升。

總結(jié)
通過排查,我們確認(rèn)了預(yù)編譯語句過多告警的根本原因是MySQL服務(wù)端開啟了預(yù)編譯緩存,導(dǎo)致過多的執(zhí)行計劃占用資源。解決方案是關(guān)閉服務(wù)端的PreparedStatement緩存,減少系統(tǒng)負(fù)載并提升性能。
到此這篇關(guān)于MySQL預(yù)編譯語句過多告警排查及解決方案的文章就介紹到這了,更多相關(guān)MySQL預(yù)編譯語句過多告警內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
windows7下啟動mysql服務(wù)出現(xiàn)服務(wù)名無效的原因及解決方法
這篇文章主要介紹了windows7下啟動mysql服務(wù)出現(xiàn)服務(wù)名無效的原因及解決方法,需要的朋友可以參考下2014-06-06
MySQL MyISAM默認(rèn)存儲引擎實現(xiàn)原理
這篇文章主要介紹了MySQL MyISAM默認(rèn)存儲引擎實現(xiàn)原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03
網(wǎng)上提供的最簡便的MySql數(shù)據(jù)庫備份的方法
網(wǎng)上提供的最簡便的MySql數(shù)據(jù)庫備份的方法...2007-02-02
mysql使用left?join連接出現(xiàn)重復(fù)問題的記錄
這篇文章主要介紹了mysql使用left?join連接出現(xiàn)重復(fù)問題的記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03

