MySQL慢查詢?nèi)罩緩呐渲玫絻?yōu)化實(shí)踐全解析
慢查詢?nèi)罩臼荕ySQL性能優(yōu)化的核心工具之一,掌握其配置、分析和優(yōu)化方法,是架構(gòu)師和DBA必備的核心技能。
本文將從基礎(chǔ)概念到實(shí)戰(zhàn)優(yōu)化,全面講解慢查詢?nèi)罩镜氖褂梅椒ê妥罴褜?shí)踐。
一、什么是慢查詢?nèi)罩?/h2>
慢查詢?nèi)罩荆⊿low Query Log)是 MySQL 內(nèi)置的日志功能,專門用于記錄執(zhí)行時(shí)間超過(guò)預(yù)設(shè)閾值(long_query_time)的 SQL 語(yǔ)句。它就像MySQL的“性能黑匣子”,能精準(zhǔn)定位執(zhí)行效率低下的SQL,是數(shù)據(jù)庫(kù)性能優(yōu)化的核心抓手。
二、核心作用
- 性能診斷:快速定位系統(tǒng)中執(zhí)行效率低的SQL語(yǔ)句,找到性能短板。
- 瓶頸定位:分析慢查詢的根因(如全表掃描、索引缺失、鎖等待等)。
- 優(yōu)化依據(jù):為SQL改寫、索引調(diào)整、數(shù)據(jù)庫(kù)參數(shù)優(yōu)化提供數(shù)據(jù)支撐。
- 容量規(guī)劃:通過(guò)慢查詢趨勢(shì),預(yù)判數(shù)據(jù)庫(kù)性能瓶頸和擴(kuò)容需求。
三、配置參數(shù)詳解
通過(guò)以下命令可查看所有慢查詢相關(guān)配置參數(shù):
-- 查看慢查詢相關(guān)參數(shù) SHOW VARIABLES LIKE '%slow%'; -- 查看慢查詢閾值參數(shù) SHOW VARIABLES LIKE '%long_query_time%';
核心配置參數(shù)說(shuō)明:
| 參數(shù)名 | 取值 | 說(shuō)明 |
|---|---|---|
slow_query_log | OFF/ON | 是否開(kāi)啟慢查詢?nèi)罩荆J(rèn)關(guān)閉) |
slow_query_log_file | 路徑字符串 | 慢查詢?nèi)罩疚募拇鎯?chǔ)路徑(如/var/log/mysql/slow.log) |
long_query_time | 數(shù)值(秒) | 慢查詢閾值,默認(rèn)10秒(MySQL 5.7+支持微秒級(jí),如0.5表示500毫秒) |
min_examined_row_limit | 數(shù)值 | 最少檢查行數(shù)閾值,低于該值的慢查詢不記錄(默認(rèn)0) |
log_queries_not_using_indexes | OFF/ON | 是否記錄未使用索引的查詢(即使執(zhí)行時(shí)間未達(dá)閾值) |
log_slow_admin_statements | OFF/ON | 是否記錄慢管理語(yǔ)句(如ALTER TABLE、ANALYZE TABLE等) |
log_output | FILE/TABLE/NONE | 日志輸出方式:文件/數(shù)據(jù)庫(kù)表/不輸出 |
四、開(kāi)啟和配置
1. 臨時(shí)開(kāi)啟(重啟失效)
適用于臨時(shí)調(diào)試,MySQL重啟后配置會(huì)恢復(fù)默認(rèn)值:
-- 開(kāi)啟慢查詢?nèi)罩? SET GLOBAL slow_query_log = 'ON'; -- 設(shè)置慢查詢閾值為2秒 SET GLOBAL long_query_time = 2; -- 指定日志文件路徑 SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; -- 記錄未使用索引的查詢 SET GLOBAL log_queries_not_using_indexes = 'ON';
2. 永久開(kāi)啟(修改配置文件)
修改MySQL配置文件(my.cnf/my.ini),重啟后生效,適用于生產(chǎn)環(huán)境:
[mysqld] # 開(kāi)啟慢查詢?nèi)罩荆?=開(kāi)啟,0=關(guān)閉) slow_query_log = 1 # 日志文件路徑 slow_query_log_file = /var/log/mysql/slow.log # 慢查詢閾值(秒) long_query_time = 2 # 記錄未使用索引的查詢 log_queries_not_using_indexes = 1 # 日志輸出到文件 log_output = FILE # 可選:記錄慢管理語(yǔ)句 log_slow_admin_statements = 1 # 可選:最少檢查行數(shù)閾值 min_examined_row_limit = 100
修改完成后重啟MySQL服務(wù):
# CentOS/RHEL systemctl restart mysqld # Ubuntu/Debian systemctl restart mysql
五、慢查詢?nèi)罩靖袷椒治?/h2>
典型日志條目
# Time: 2024-01-01T10:00:00.123456Z # User@Host: root[root] @ localhost [] Id: 5 # Query_time: 5.123456 Lock_time: 0.001000 Rows_sent: 10 Rows_examined: 1000000 SET timestamp=1672560000; SELECT * FROM users WHERE last_name LIKE '%smith%' ORDER BY create_time DESC;
關(guān)鍵字段解釋
| 字段名 | 說(shuō)明 |
|---|---|
Time | 查詢執(zhí)行的時(shí)間戳(UTC時(shí)間) |
User@Host | 執(zhí)行查詢的用戶和主機(jī)信息 |
Id | 數(shù)據(jù)庫(kù)連接ID |
Query_time | 查詢總執(zhí)行時(shí)間(秒,含微秒) |
Lock_time | 查詢過(guò)程中鎖等待時(shí)間(秒) |
Rows_sent | 返回給客戶端的行數(shù) |
Rows_examined | 數(shù)據(jù)庫(kù)掃描的行數(shù)(核心指標(biāo),行數(shù)越多性能越差) |
Rows_affected | 受DML語(yǔ)句(UPDATE/DELETE/INSERT)影響的行數(shù) |
timestamp | 查詢開(kāi)始的UNIX時(shí)間戳 |
六、慢查詢分析工具
1. mysqldumpslow(MySQL 自帶)
MySQL內(nèi)置的輕量級(jí)分析工具,無(wú)需額外安裝,適合快速匯總慢查詢:
# 按查詢時(shí)間排序,顯示最慢的前10條 mysqldumpslow -s t -t 10 /var/log/mysql/slow.log # 按執(zhí)行次數(shù)排序 mysqldumpslow -s c /var/log/mysql/slow.log # 按鎖時(shí)間排序 mysqldumpslow -s l /var/log/mysql/slow.log # 分析特定用戶的慢查詢(保留原始SQL) mysqldumpslow -a -g "root" /var/log/mysql/slow.log
2. pt-query-digest(Percona Toolkit)
Percona出品的專業(yè)分析工具,功能強(qiáng)大,是生產(chǎn)環(huán)境首選:
安裝(以CentOS為例):
yum install percona-toolkit -y
常用命令:
# 基礎(chǔ)分析,輸出詳細(xì)報(bào)告 pt-query-digest /var/log/mysql/slow.log # 分析最近12小時(shí)的慢查詢 pt-query-digest --since=12h /var/log/mysql/slow.log # 分析指定時(shí)間段的慢查詢 pt-query-digest --since='2024-01-01 00:00:00' --until='2024-01-01 23:59:59' /var/log/mysql/slow.log # 將分析結(jié)果輸出到文件 pt-query-digest /var/log/mysql/slow.log > /tmp/slow_report_$(date +%Y%m%d).txt
3. mysqlslow(第三方工具)
輕量級(jí)第三方工具,安裝簡(jiǎn)單,輸出結(jié)果直觀:
# 安裝(需先安裝pip) pip install mysqlslow # 分析慢查詢?nèi)罩? mysqlslow /var/log/mysql/slow.log
七、慢查詢?nèi)罩颈砟J?/h2>
除了文件存儲(chǔ),MySQL還支持將慢查詢?nèi)罩敬鎯?chǔ)到數(shù)據(jù)庫(kù)表中,便于SQL查詢分析。
啟用表模式存儲(chǔ):
-- 設(shè)置日志輸出到表(FILE,TABLE 表示同時(shí)輸出到文件和表) SET GLOBAL log_output = 'TABLE'; -- 開(kāi)啟慢查詢?nèi)罩? SET GLOBAL slow_query_log = 'ON'; -- 查詢慢查詢?nèi)罩颈? SELECT * FROM mysql.slow_log;
表結(jié)構(gòu):
SHOW CREATE TABLE mysql.slow_log;
核心字段說(shuō)明:
| 字段名 | 類型 | 說(shuō)明 |
|---|---|---|
start_time | DATETIME(6) | 查詢開(kāi)始時(shí)間(含微秒) |
query_time | TIME(6) | 查詢執(zhí)行時(shí)間 |
lock_time | TIME(6) | 鎖等待時(shí)間 |
rows_sent | INT UNSIGNED | 返回行數(shù) |
rows_examined | INT UNSIGNED | 掃描行數(shù) |
sql_text | LONGTEXT | SQL語(yǔ)句內(nèi)容 |
user_host | MEDIUMTEXT | 用戶和主機(jī)信息 |
注意:表模式存儲(chǔ)會(huì)增加數(shù)據(jù)庫(kù)寫入壓力,生產(chǎn)環(huán)境建議優(yōu)先使用文件模式。
八、最佳實(shí)踐和優(yōu)化建議
1. 閾值設(shè)置建議
閾值需根據(jù)業(yè)務(wù)場(chǎng)景調(diào)整,避免記錄過(guò)多無(wú)效日志或遺漏關(guān)鍵慢查詢:
-- 生產(chǎn)環(huán)境(平衡性能和排查需求) SET GLOBAL long_query_time = 2; -- 2秒閾值 -- 開(kāi)發(fā)/測(cè)試環(huán)境(嚴(yán)格排查) SET GLOBAL long_query_time = 0.5; -- 500毫秒 -- 高并發(fā)核心業(yè)務(wù)(微秒級(jí)監(jiān)控,MySQL 5.7+) SET GLOBAL long_query_time = 0.1; -- 100毫秒
2. 日志輪轉(zhuǎn)配置
避免慢查詢?nèi)罩疚募^(guò)大,使用logrotate實(shí)現(xiàn)日志自動(dòng)輪轉(zhuǎn):
# /etc/logrotate.d/mysql-slow
/var/log/mysql/slow.log {
daily # 每日輪轉(zhuǎn)
rotate 30 # 保留30天日志
missingok # 日志文件不存在時(shí)不報(bào)錯(cuò)
compress # 壓縮舊日志
delaycompress # 延遲壓縮(保留最新的輪轉(zhuǎn)文件未壓縮)
notifempty # 空文件不輪轉(zhuǎn)
create 640 mysql mysql # 新建日志文件的權(quán)限和屬主
postrotate # 輪轉(zhuǎn)后執(zhí)行的命令
mysqladmin flush-logs # 刷新日志,生成新文件
endscript
}3. 定期分析計(jì)劃
編寫自動(dòng)化腳本,每日分析慢查詢并歸檔,示例:
#!/bin/bash
# /usr/local/bin/analyze_slow_log.sh
# 腳本功能:每日分析慢查詢?nèi)罩静w檔
# 定義變量
DATE=$(date +%Y%m%d)
LOG_PATH="/var/log/mysql"
REPORT_PATH="${LOG_PATH}/reports"
SLOW_LOG="${LOG_PATH}/slow.log"
# 創(chuàng)建報(bào)告目錄
mkdir -p ${REPORT_PATH}
# 使用pt-query-digest分析日志并生成報(bào)告
pt-query-digest ${SLOW_LOG} > ${REPORT_PATH}/slow_report_${DATE}.txt
# 備份并清空原日志文件
cp ${SLOW_LOG} ${LOG_PATH}/slow.log.${DATE}
> ${SLOW_LOG}
# 清理30天前的舊報(bào)告
find ${REPORT_PATH} -name "slow_report_*.txt" -mtime +30 -delete添加到crontab,每日凌晨執(zhí)行:
# 編輯crontab crontab -e # 添加以下內(nèi)容 0 0 * * * /usr/local/bin/analyze_slow_log.sh > /dev/null 2>&1
九、性能監(jiān)控和告警
1. 監(jiān)控慢查詢數(shù)量
通過(guò)MySQL狀態(tài)變量實(shí)時(shí)監(jiān)控慢查詢數(shù)量:
-- 查看累計(jì)慢查詢數(shù)量 SHOW GLOBAL STATUS LIKE 'Slow_queries'; -- 查看當(dāng)前正在執(zhí)行的慢查詢 SHOW PROCESSLIST; -- 或更詳細(xì)的信息 SHOW FULL PROCESSLIST;
2. 慢查詢告警腳本
編寫腳本監(jiān)控慢查詢數(shù)量,超過(guò)閾值時(shí)發(fā)送告警:
#!/bin/bash
# /usr/local/bin/slow_query_alert.sh
# 配置參數(shù)
MYSQL_CMD="mysql -uroot -p'你的密碼' -e"
THRESHOLD=100 # 慢查詢閾值
ALERT_EMAIL="admin@example.com"
# 獲取當(dāng)前慢查詢總數(shù)
SLOW_COUNT=$($MYSQL_CMD "SHOW GLOBAL STATUS LIKE 'Slow_queries'" | grep Slow_queries | awk '{print $2}')
# 對(duì)比閾值并發(fā)送告警
if [ $SLOW_COUNT -gt $THRESHOLD ]; then
SUBJECT="【告警】MySQL慢查詢數(shù)量異常"
CONTENT="當(dāng)前慢查詢總數(shù):${SLOW_COUNT},超過(guò)閾值${THRESHOLD}!\n請(qǐng)及時(shí)登錄數(shù)據(jù)庫(kù)排查慢查詢。"
echo -e ${CONTENT} | mail -s "${SUBJECT}" ${ALERT_EMAIL}
fi添加到crontab,每分鐘執(zhí)行一次:
* * * * * /usr/local/bin/slow_query_alert.sh > /dev/null 2>&1
十、注意事項(xiàng)
- 性能影響:開(kāi)啟慢查詢?nèi)罩緯?huì)增加約1-3%的數(shù)據(jù)庫(kù)性能開(kāi)銷(主要是磁盤I/O),生產(chǎn)環(huán)境需評(píng)估后開(kāi)啟。
- 磁盤空間:慢查詢?nèi)罩驹鲩L(zhǎng)較快,必須配置日志輪轉(zhuǎn),避免占滿磁盤。
- 敏感信息:日志中可能包含用戶密碼、業(yè)務(wù)敏感數(shù)據(jù),需限制日志文件的訪問(wèn)權(quán)限(如僅root和mysql用戶可讀?。?。
- 版本差異:MySQL 5.7+支持
long_query_time的微秒級(jí)精度,5.6及以下版本僅支持秒級(jí);8.0版本默認(rèn)日志格式有小幅調(diào)整。 - 測(cè)試驗(yàn)證:開(kāi)啟慢查詢后,需執(zhí)行
SELECT SLEEP(3);(假設(shè)閾值為2秒)驗(yàn)證日志是否正常記錄。 - 索引記錄:
log_queries_not_using_indexes開(kāi)啟后,會(huì)記錄大量簡(jiǎn)單的無(wú)索引查詢(如SELECT * FROM t LIMIT 1),需結(jié)合min_examined_row_limit過(guò)濾。
面試回答(精簡(jiǎn)版)
慢查詢?nèi)罩臼荕ySQL記錄執(zhí)行時(shí)間超過(guò)閾值SQL的核心工具,就像數(shù)據(jù)庫(kù)的“性能病歷本”,是優(yōu)化的關(guān)鍵依據(jù)。
核心回答要點(diǎn):
- 開(kāi)啟配置:生產(chǎn)環(huán)境通過(guò)修改
my.cnf永久開(kāi)啟,核心參數(shù)包括slow_query_log=1(開(kāi)啟)、long_query_time=2(閾值)、log_queries_not_using_indexes=1(記錄無(wú)索引查詢)。 - 分析工具:常用
mysqldumpslow(快速匯總)和pt-query-digest(專業(yè)分析),重點(diǎn)關(guān)注Query_time(執(zhí)行時(shí)間)、Rows_examined(掃描行數(shù))等字段。 - 優(yōu)化思路:找到慢查詢后,用
EXPLAIN分析執(zhí)行計(jì)劃,核心優(yōu)化手段包括:添加合適的索引、改寫SQL(避免SELECT *、優(yōu)化子查詢)、調(diào)整數(shù)據(jù)庫(kù)參數(shù)(如緩沖池)。 - 最佳實(shí)踐:生產(chǎn)環(huán)境設(shè)置合理閾值(2秒),配置日志輪轉(zhuǎn),定期自動(dòng)分析并設(shè)置告警,平衡性能開(kāi)銷和問(wèn)題排查需求。
總結(jié)
- 慢查詢?nèi)罩臼荕ySQL性能優(yōu)化的核心工具,核心配置參數(shù)為
slow_query_log(開(kāi)關(guān))、long_query_time(閾值)、log_queries_not_using_indexes(無(wú)索引查詢記錄)。 - 生產(chǎn)環(huán)境建議通過(guò)修改配置文件永久開(kāi)啟,結(jié)合
logrotate實(shí)現(xiàn)日志輪轉(zhuǎn),使用pt-query-digest進(jìn)行專業(yè)分析。 - 慢查詢優(yōu)化的核心思路是:通過(guò)日志定位慢SQL → 用
EXPLAIN分析執(zhí)行計(jì)劃 → 針對(duì)性優(yōu)化(加索引/改SQL/調(diào)參數(shù)),并建立定期分析和告警機(jī)制。
到此這篇關(guān)于MySQL慢查詢?nèi)罩緩呐渲玫絻?yōu)化實(shí)踐全解析的文章就介紹到這了,更多相關(guān)mysql慢查詢?nèi)罩緝?nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL數(shù)據(jù)庫(kù)改名的三種實(shí)現(xiàn)方式
這篇文章主要介紹了MySQL數(shù)據(jù)庫(kù)改名的三種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
mssql2008 自定義表類型實(shí)現(xiàn)(批量插入或者修改)
在做大型網(wǎng)站或者系統(tǒng)的時(shí)候,經(jīng)常會(huì)遇到個(gè)問(wèn)題就是批量插入或者修改數(shù)據(jù)庫(kù);今天這邊不講SqlBulkCopy,只簡(jiǎn)單講sql自定義表類型,感興趣的朋友可以了解下哦,希望本文對(duì)你有所幫助2013-01-01
SQL?Server攜程核心系統(tǒng)無(wú)感遷移到MySQL實(shí)戰(zhàn)
這篇文章主要介紹了SQL?Server攜程核心系統(tǒng)無(wú)感遷移到MySQL實(shí)戰(zhàn),文章通過(guò)基于數(shù)據(jù)庫(kù)部署架構(gòu)鏡像構(gòu)建了訂單緩存統(tǒng)一管理熱點(diǎn)數(shù)據(jù),解決各端差異,具體詳情需要的小伙伴可以參考下面文章詳細(xì)內(nèi)容2022-05-05
MySQL優(yōu)化教程之慢查詢?nèi)罩緦?shí)踐
在MySQL中慢查詢?nèi)罩局饕脕?lái)記錄響應(yīng)時(shí)間超過(guò)閾值的SQL,下面這篇文章主要給大家介紹了關(guān)于MySQL優(yōu)化教程之慢查詢?nèi)罩镜南嚓P(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06
MySQL中sleep函數(shù)的特殊現(xiàn)象示例詳解
這篇文章主要給大家介紹了關(guān)于MySQL中sleep函數(shù)特殊現(xiàn)象的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用MySQL具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
MySQL通用表空間的幾個(gè)選項(xiàng)使用指南
在?MySQL?數(shù)據(jù)庫(kù)中有效管理存儲(chǔ)和性能至關(guān)重要,通用表空間為實(shí)現(xiàn)這一目標(biāo)提供了靈活性,本文討論通用表空間并探討其功能、優(yōu)點(diǎn)和實(shí)際用法,并附有說(shuō)明性示例2024-01-01
MySQL之undo日志頁(yè)結(jié)構(gòu)詳解
這篇文章主要介紹了MySQL之undo日志頁(yè)結(jié)構(gòu),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06
SQL語(yǔ)句在MySQL的執(zhí)行過(guò)程詳解
這篇文章主要介紹了SQL語(yǔ)句在MySQL的執(zhí)行過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-05-05

