線上資料庫因頻繁上線、缺乏效能把關,導致響應極慢甚至宕機。本文記錄一次真實優化案例:透過慢查詢日誌分析、建立分析表、聚焦高頻慢 SQL、釋放事務鎖、優化索引,將慢查詢從每小時 1000 筆降至 100 筆,平均查詢時間從 2.6s 降至 0.5s 以下的完整過程與關鍵 SQL 技巧。
long_query_time = 2 秒
# my.cnf
slow_query_log = 1
slow_query_log_file = /var/lib/mysql/slow.log
long_query_time = 2
log_queries_not_using_indexes = 1
CREATE TABLE slow_query (
`Date` varchar(32) NOT NULL,
`user` varchar(64) NOT NULL,
`host` varchar(64) NOT NULL,
`content` text NOT NULL COMMENT '正規化後的 SQL 模板,便於 GROUP BY',
`query_time` int(11) NOT NULL COMMENT '查詢耗時(秒),核心指標',
`lock_time` int(11) DEFAULT 0 COMMENT '鎖等待時間',
`rows_sent` int(11) DEFAULT 0 COMMENT '回傳行數',
`rows_examined` int(11) DEFAULT 0 COMMENT '掃描行數,超過萬筆需重點關注',
`statement` text COMMENT '原始 SQL'
);
編寫腳本解析 mysqldumpslow 或直接正則解析慢查詢日誌,匯入上表。
-- 優化前
SELECT SUM(query_time)/COUNT(*) AS avg_q, COUNT(*), SUM(query_time), MIN(Date), MAX(Date)
FROM slow_query
WHERE Date > '2008-02-17 22:50:52' AND Date < '2008-02-18 17:34:35';
-- 結果:平均 2.5983s,16,091 筆,總 41,810s
-- 優化後
SELECT SUM(query_time)/COUNT(*) AS avg_q, COUNT(*), SUM(query_time), MIN(Date), MAX(Date)
FROM slow_query
WHERE Date > '2008-02-20 22:50:52' AND Date < '2008-02-21 17:34:35';
-- 結果:平均 5.7233s,2,197 筆,總 12,574s
筆數大幅下降(16k → 2k),總耗時降 70%,但平均耗時上升因剩餘為難啃的硬骨頭。
SELECT COUNT(*) AS n, SUM(query_time) AS s, SUM(query_time)/COUNT(*) AS avg,
SUBSTRING_INDEX(statement, ' ', 2) AS sql_type
FROM slow_query
WHERE statement LIKE 'update%' AND query_time > 14
GROUP BY sql_type;
+-----+------+---------+--------------------------+
| n | s | avg | sql_type |
+-----+------+---------+--------------------------+
| 7 | 112 | 16.00 | update conversation |
| 151 | 2413 | 15.98 | update user |
| 4 | 65 | 16.25 | update user_modification |
+-----+------+---------+--------------------------+
結論:大量 UPDATE 耗時 16 秒,明顯是事務鎖未釋放(長事務、死鎖或忘記 COMMIT)。修正程式碼確保事務最小化、及時提交。
SELECT SUM(query_time) AS sum_t, COUNT(*) AS cnt, SUM(query_time)/COUNT(*) AS avg_t, statement
FROM slow_query
WHERE host LIKE '%69.12.23.%'
GROUP BY content
ORDER BY sum_t DESC LIMIT 10;
前 3 筆屬同類查詢,佔總查詢 50%+,每分鐘 10+ 筆,優先解決。
EXPLAIN 發現全表掃描,加上複合索引覆蓋 WHERE + ORDER BYLIMIT 100000, 20 → 游標分頁 WHERE id > last_id LIMIT 20Slow_queries、Queries_per_sec、Innodb_row_lock_waits| 工具 | 用途 |
|---|---|
mysqldumpslow |
官方日誌摘要分析 |
pt-query-digest |
Percona 深度分析(推薦) |
EXPLAIN / EXPLAIN ANALYZE |
執行計畫驗證 |
SHOW ENGINE INNODB STATUS |
鎖/死鎖/事務監控 |
performance_schema |
5.6+ 內建語句級統計 |
優化沒有終點,只有持續迭代。建立「慢查詢日誌 → 歸因分析 → 針對性修復 → 效果驗證 → 固化規範」的閉環機制,才能讓資料庫長期保持健康狀態。