很多開發者拿到慢 SQL 就加索引、調緩衝池,卻不知系統真正瓶頸在哪。優化第一步是**建立可觀測指標體系**,精準定位「是查詢慢、鎖爭用、IO 瓶頸、還是配置不當」。本文梳理關鍵狀態變量與慢查詢配置標準流程。
執行 SHOW GLOBAL STATUS(或 SHOW STATUS 當前會話),重點關注以下累計計數器:
| 變量 | 含義 | 異常判斷 |
|---|---|---|
Com_select | SELECT 執行次數 | QPS 基線 |
Com_insert/Com_update/Com_delete | 寫操作次數 | 寫入熱點 |
Connections | 嘗試連接總數 | 連接風暴 |
Uptime | 服務運行秒數 | 計算各項 Per Second |
Slow_queries | 慢查詢次數 | > 0 即需關注 |
Threads_connected | 當前連接數 | 接近 max_connections 報警 |
Innodb_row_lock_waits | 行鎖等待次數 | 鎖爭用熱點 |
Innodb_buffer_pool_reads | 磁盤讀取次數(未命中) | 緩衝池過小 |
Created_tmp_disk_tables | 磁盤臨時表次數 | SQL 排序/分組優化 |
-- 手動計算 QPS/TPS
SELECT
VARIABLE_VALUE INTO @qps FROM performance_schema.global_status WHERE VARIABLE_NAME='Questions';
SELECT SLEEP(10);
SELECT
(VARIABLE_VALUE - @qps) / 10 AS qps_10s
FROM performance_schema.global_status WHERE VARIABLE_NAME='Questions';
-- TPS = (Com_commit + Com_rollback) / 秒
-- 若用 XA 事務,加上 Com_xa_commit + Com_xa_rollback
生產環境建議接入 **Prometheus + Grafana** 或 **Datadog** 自動采集繪圖。
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; -- 超過 1 秒記錄(微秒精度可用 0.05) SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; SET GLOBAL log_queries_not_using_indexes = 'ON'; -- 記錄未走索引的查詢
持久化寫入 my.cnf:
[mysqld] slow_query_log = 1 long_query_time = 1 slow_query_log_file = /var/log/mysql/slow.log log_queries_not_using_indexes = 1 log_slow_admin_statements = 1 log_slow_slave_statements = 1
mysqldumpslow -s t -t 20 /var/log/mysql/slow.log(按時間排序顯示前 20)pt-query-digest /var/log/mysql/slow.log --limit 20 --filter '$event->{bytes} > 100000'SELECT * FROM sys.schema_table_statistics_with_buffer ORDER BY io_read_requests DESC LIMIT 10;# Time: 2024-01-15T10:30:00.123456Z # User@Host: app[app] @ 10.0.1.5 # Query_time: 2.345 Lock_time: 0.001 Rows_sent: 10 Rows_examined: 1000000 SET timestamp=1705314600; SELECT * FROM orders WHERE user_id=123 AND status=1 ORDER BY created_at DESC LIMIT 10;
Query_time:總耗時(含鎖等待、IO、CPU)。Lock_time:等待鎖時間,大於 0.1s 提示鎖爭用。Rows_examined:掃描行數,**遠大於 Rows_sent 表明全表掃描或索引失效**。pt-query-digest 產出 Top 10 慢 SQL,按 Query_time * Exec_count 總耗時排序,鎖定「高頻慢」與「低頻極慢」。EXPLAIN、EXPLAIN ANALYZE(8.0.18+)、OPTIMIZER_TRACE,確認訪問類型、索引使用、掃描行數、臨時表/文件排序。| 誤區 | 正確做法 |
|---|---|
只看 long_query_time=10 默認值 | 業務核心鏈路設 0.5~1 秒,全量開啟 |
| 慢查詢日誌只記錄慢 SQL | 開啟 log_queries_not_using_indexes 發現潛在全掃 |
| 直接加索引不驗證 | EXPLAIN 前後對比,觀察 rows、filtered、Extra |
調大 innodb_buffer_pool_size 就完事 | 先看 Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests 未命中率 > 1% 再調 |