# MySQL的慢SQL怎么優化
## 前言
在數據庫運維和開發過程中,慢SQL是影響系統性能的常見問題。當SQL查詢執行時間超過預期閾值時,不僅會導致用戶體驗下降,還可能引發數據庫連接池耗盡、服務器資源過載等連鎖反應。本文將系統性地介紹MySQL慢SQL的優化方法,涵蓋監控識別、分析診斷、優化方案和預防措施等方面內容。
## 一、什么是慢SQL
### 1.1 定義
慢SQL是指執行時間超過預設閾值的SQL語句。在MySQL中,默認的慢查詢閾值是10秒(可通過`long_query_time`參數調整)。
### 1.2 影響
- 系統資源消耗增加
- 并發處理能力下降
- 用戶體驗惡化
- 可能引發雪崩效應
## 二、如何發現慢SQL
### 2.1 慢查詢日志
```sql
-- 開啟慢查詢日志
SET GLOBAL slow_query_log = 'ON';
-- 設置慢查詢閾值(秒)
SET GLOBAL long_query_time = 2;
-- 記錄未使用索引的查詢
SET GLOBAL log_queries_not_using_indexes = 'ON';
-- 查看當前運行的慢查詢
SELECT * FROM information_schema.PROCESSLIST
WHERE TIME > 10 AND COMMAND != 'Sleep';
-- 查詢performance_schema中的語句統計
SELECT * FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WT DESC LIMIT 10;
EXPLN FORMAT=JSON SELECT * FROM orders WHERE user_id = 100;
關鍵指標解讀: - type:從優到差依次為 system > const > eq_ref > ref > range > index > ALL - key:實際使用的索引 - rows:預估掃描行數 - Extra:重要補充信息(Using filesort, Using temporary等)
-- 開啟會話級性能分析
SET profiling = 1;
-- 執行待分析的SQL
SELECT * FROM large_table WHERE condition;
-- 查看分析結果
SHOW PROFILE;
-- 查看詳細IO和CPU消耗
SHOW PROFILE BLOCK IO, CPU FOR QUERY 1;
-- 1. 隱式類型轉換
SELECT * FROM users WHERE phone = 13800138000; -- phone是varchar類型
-- 2. 函數操作索引列
SELECT * FROM orders WHERE DATE(create_time) = '2023-01-01';
-- 3. 前導模糊查詢
SELECT * FROM products WHERE name LIKE '%手機%';
-- 4. 不滿足最左前綴
ALTER TABLE users ADD INDEX idx_composite(name, age);
SELECT * FROM users WHERE age > 20; -- 無法使用索引
-- 優化前(全表掃描)
SELECT * FROM orders WHERE status = 'completed' AND create_time > '2023-01-01';
-- 優化后(添加復合索引)
ALTER TABLE orders ADD INDEX idx_status_time(status, create_time);
-- 原查詢(嵌套子查詢)
SELECT * FROM users WHERE id IN (
SELECT user_id FROM orders WHERE amount > 1000
);
-- 優化為JOIN
SELECT u.* FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.amount > 1000;
-- 低效寫法
SELECT * FROM large_table LIMIT 1000000, 10;
-- 優化方案1:使用主鍵分頁
SELECT * FROM large_table WHERE id > 1000000 LIMIT 10;
-- 優化方案2:延遲關聯
SELECT t.* FROM large_table t
JOIN (SELECT id FROM large_table LIMIT 1000000, 10) tmp ON t.id = tmp.id;
-- 低效做法(應用程序循環)
for id in ids:
DELETE FROM table WHERE id = id
-- 高效批量操作
DELETE FROM table WHERE id IN (1,2,3,...);
[mysqld]
# 緩沖池大?。ńㄗh物理內存的50-75%)
innodb_buffer_pool_size = 12G
# 日志文件大小
innodb_log_file_size = 2G
# 連接數設置
max_connections = 500
thread_cache_size = 50
# 排序緩沖區
sort_buffer_size = 4M
join_buffer_size = 4M
-- 合理設置隔離級別
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- 控制事務大小
START TRANSACTION;
-- 批量插入10萬條數據
INSERT INTO ... VALUES (...), (...), ...;
COMMIT;
-- 創建匯總表
CREATE TABLE sales_summary (
product_id INT PRIMARY KEY,
total_sales DECIMAL(12,2),
last_updated TIMESTAMP
);
-- 定期刷新
REPLACE INTO sales_summary
SELECT product_id, SUM(amount), NOW()
FROM orders
GROUP BY product_id;
-- 8.0+版本支持
SELECT /*+ PARALLEL(4) */ * FROM large_table WHERE condition;
-- 使用列式存儲處理分析型查詢
ALTER TABLE analytics_data ENGINE=ColumnStore;
-- 創建監控表
CREATE TABLE slow_query_monitor (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
query_digest VARCHAR(32),
sample_query TEXT,
exec_count INT,
avg_latency DECIMAL(10,3),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 定期從performance_schema采集數據
INSERT INTO slow_query_monitor(query_digest, sample_query, exec_count, avg_latency)
SELECT DIGEST_TEXT, DIGEST, COUNT_STAR, AVG_TIMER_WT/1000000000
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WT DESC LIMIT 10;
工具名稱 | 用途 | 官網 |
---|---|---|
pt-query-digest | 慢日志分析 | percona.com |
sysbench | 壓力測試 | github.com/akopytov/sysbench |
gh-ost | 在線DDL工具 | github.com/github/gh-ost |
Atlas | SQL中間件 | github.com/Qihoo360/Atlas |
注:本文基于MySQL 8.0版本編寫,部分特性在早期版本可能不適用。實際生產環境優化時,請務必先在測試環境驗證。 “`
(全文約6550字,實際字數可能因排版有所差異)
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。