MySQL 作為最流行的開源關係型數據庫,其性能優化始終是開發者與 DBA 關注的核心課題。本文整理了 19 條經過生產環境驗證的優化實踐,涵蓋查詢緩存、索引設計、SQL 改寫、架構選型等關鍵領域,助你構建高性能的數據庫系統。
MySQL 內建的查詢緩存能顯著提升重複查詢的響應速度。但需注意:NOW()、RAND()、CURDATE() 等非確定性函數會導致緩存失效。
-- 緩存失效示例
SELECT username FROM user WHERE signup_date >= CURDATE();
-- 優化後:使用變量替代函數
SET @today = '2024-01-15';
SELECT username FROM user WHERE signup_date >= @today;
核心原則:將動態函數計算移至應用層,保持 SQL 語句確定性,充分發揮查詢緩存效能。
EXPLAIN 是 SQL 調優的「聽診器」。通過分析 type、key、rows、Extra 等關鍵列,可精準定位全表掃描、索引缺失、臨時表創建等性能殺手。
實戰案例:某雙表關聯查詢緩慢,EXPLAIN 顯示 type=ALL,在關聯字段 group_id 建立索引後,類型變為 ref,查詢耗時從秒級降至毫秒級。
LIMIT 1 讓存儲引擎在找到第一條匹配記錄後立即停止掃描。-- 低效寫法
SELECT * FROM user WHERE country = 'China';
-- 高效寫法
SELECT 1 FROM user WHERE country = 'China' LIMIT 1;
DECIMAL 不能與 INT 關聯;字符串類型需統一字符集(如均為 utf8mb4),否則索引失效。推薦 BIGINT UNSIGNED AUTO_INCREMENT 作為主鍵。業務鍵(如 email、UUID)作為主鍵會導致:
狀態、性別、類型等枚舉值固定的字段,使用 ENUM 存儲效率極高(實際佔 1-2 字節),查詢速度優於 VARCHAR。
基於現有數據分析字段類型優化建議(如 INT → MEDIUMINT,VARCHAR → ENUM),但需結合業務增長預期謹慎決策。
NULL 需額外存儲空間(MyISAM 每列 1 bit,InnoDB 更複雜),且比較運算邏輯複雜(NULL != NULL)。除非業務強制語義需要,否則定義為 NOT NULL DEFAULT '默認值'。
INET_ATON() / INET_NTOA() 轉換,僅佔 4 字節,範圍查詢(BETWEEN)極其高效,節省 60% 存儲空間。
無 VARCHAR/TEXT/BLOB 的表為「靜態表」,MySQL 可通過位移量直接定位行,掃描速度提升 20%-30%,緩存友好。權衡:固定長度會浪費空間,需根據業務場景取捨。
大批量 DELETE/INSERT 會持有表鎖/行鎖導致並發阻塞,甚至觸發主從延遲、連接數爆增引發雪崩。
-- 分批刪除模板
WHILE 1 DO
DELETE FROM logs WHERE log_date <= '2023-01-01' LIMIT 1000;
IF ROW_COUNT() = 0 THEN LEAVE; END IF;
DO SLEEP(0.05); -- 釋放鎖,緩解主從壓力
END WHILE;
參考 Storage Requirements 選擇最精簡類型:
SMALLINT/TINYINTDATE 代替 DATETIMEALTER TABLE 擴展 INT 主鍵耗時 3+ 小時(1600 萬行)| 維度 | MyISAM | InnoDB |
|---|---|---|
| 鎖粒度 | 表鎖 | 行鎖 |
| 事務支持 | 無 | ACID 完整支持 |
| 查詢性能 | 純讀極快(COUNT(*) 秒級) | 寫多場景優秀 |
| 崩壞恢復 | 需修復 | Redo/Undo Log 自動恢復 |
選型建議:
• 讀多寫少、無事務、全文搜索場景 → MyISAM
• 高並發寫入、事務強一致、高可用架構 → InnoDB(現代應用首選)
mysql_pconnect() 雖減少握手開銷,但易導致:
推薦:短連接 + 連接池(如 HikariCP、Druid),配合 wait_timeout、max_connections 精準控制。
MySQL 對 IN (subquery) 優化較弱,易退化為 DEPENDENT SUBQUERY(外層表每行執行一次子查詢)。
-- 原始慢查詢 (18.87s)
SELECT * FROM guang_deal_outs
WHERE deal_id IN (SELECT id FROM guang_deals WHERE id = 100017151);
-- 優化為 JOIN (0.01s)
SELECT a.* FROM guang_deal_outs a
INNER JOIN guang_deals b ON a.deal_id = b.id
WHERE b.id = 100017151;
原理:JOIN 允許優化器選擇驅動表,利用索引 ref 訪問;IN 子查詢常被執行為 EXISTS 關聯,外層表大時性能崩塌。
MySQL 優化無銀彈,需結合:
performance_schema 監控、定期 ANALYZE TABLE 更新統計信息持續建立「慢查詢治理 → 驗證效果 → 沉澱規範」的閉環,方能構建穩定高效的數據庫服務。