資料庫效能優化是系統架構的核心竞争力。本文蒐羅 MySQL 效能調優的精華法則:從資料型選型原則、索引設計鐵律、InnoDB 獨特機制 (自適應雜湊、聚簇索引、MVCC) 到查詢緩存陷阱,構建系統化知識圖譜,助你從「經驗調優」進化為「原理驅動優化」。
TINYINT 代替 INT、DATE 代替 DATETIME),減少磁碟 I/O、記憶體佔用、CPU 快取未命中。INT, DATE, VARCHAR),避免複雜型別 (JSON, GEOMETRY, ENUM, SET) 除非業務強依賴其特性。複雜型別解析、比較、索引開銷大。NOT NULL + DEFAULT。NULL 需額外位圖標記、索引統計複雜、COUNT(col) 語義陷阱、應用層須額外判空。效能增益雖微但可維護性顯著提升。| 場景 | 推薦型別 | 理由 |
|---|---|---|
| 長度固定、極短 (MD5/UUID/國別碼/狀態碼) | CHAR | 無長度開銷、固定偏移極快、無碎片 |
| 平均長度 << 最大長度、低頻更新 (文章、評論、描述) | VARCHAR | 節省空間、提升緩存命中、減少 I/O |
| 高頻更新、長度變化大 | VARCHAR + 預留空間 | InnoDB 頁內移動開銷可控,仍優於 CHAR 浪費空間 |
| 超長文本 (日誌、文檔) | TEXT/LONGTEXT | 溢頁儲存,不阻塞主表掃描 |
核心洞察:InnoDB 頁大小 16KB,VARCHAR 變長更新導致的行遷移發生在記憶體頁內,經測試對整體效能影響可忽略。**空間效率 (更多行/頁) 帶來的 I/O 減少遠大於 CPU 解析成本**。
BIGINT UNSIGNED AUTO_INCREMENT)。索引列值 + 主鍵值。INDEX idx_a_b_c (a, b, c)
-- 可用:a | a,b | a,b,c
-- 不可用:b | b,c | c | a,c (c 斷層)
優化器僅能高效利用**最左連續前綴**。
COUNT(DISTINCT col) / COUNT(*)。越接近 1 越好 (唯一鍵=1)。INDEX idx_url_prefix (url(19))。長度取值使選擇性接近全列 (通常 15-20 字元)。SHOW PROFILE, EXPLAIN ANALYZE (8.0+), sys.schema_unused_indexes 找出高耗時、高負載、未使用索引。(a,b,c) 好過三個 (a), (b), (c)。PRIMARY KEY (id) + INDEX (id)) 必須清理。| 特性 | 機制 | 效能影響 | 調優建議 |
|---|---|---|---|
| 事務 (ACID) | Redo Log (WAL) + Undo Log (MVCC) | 持久化與並發基石 | innodb_flush_log_at_trx_commit=1 (強一致) / =2 (高效能) |
| 行級鎖 | 記錄鎖/間隙鎖/Next-Key Lock | 高並發寫入優勢 | 盡量用主鍵/唯一鍵精準定位,避免範圍掃描升級間隙鎖 |
| MVCC | Read View + Undo Log 版本鏈 | 非鎖定一致性讀 (RR 隔離級別) | 長事務阻塞 Purge,導致 Undo 膨脹、歷史版本堆積,嚴禁長事務 |
| 自適應雜湊索引 (AHI) | 熱點頁 B+ 樹頂層建立 Hash 索引 | 熱點查詢 O(1) 級加速 | innodb_adaptive_hash_index=ON (預設),觀察 Innodb_buffer_pool_wait_free |
| Change Buffer | 非唯一二級索引寫入緩衝,後台合併 | 減少隨機 I/O,寫入加速 | 讀多寫少場景關閉 innodb_change_buffering=none |
| Doublewrite Buffer | 頁刷盤前先寫共享表空間,防止斷電頁損壞 | 資料安全,微小寫入開銷 | SSD 可考慮關閉 innodb_doublewrite=OFF (需檔案系統支援原子寫入) |
機制:Query Text (Key) → Result Set (Value) 的 Hash Map。**大小寫敏感、空格敏感、註釋敏感** → 任何差異導致未命中。
不緩存場景:含不確定函數 (NOW(), RAND(), UUID())、用戶變數、SELECT ... LOCK IN SHARE MODE、結果集超過 query_cache_limit、系統表、分區表。
開銷:每次查詢需檢查緩存、寫入需失效相關緩存、記憶體碎片化、鎖競爭 (query_cache_mutex)。
實測:寫入佔比 > 10-20% 時,緩存往往**拖慢整體吞吐**。
建議:
- 讀多寫極少 (配置表、字典表) → 可開啟並設定 query_cache_type=DEMAND、SQL_CACHE 顯式控制。
- 通用 OLTP → **關閉 (query_cache_type=OFF, query_cache_size=0)**,依賴應用層緩存 (Redis) 與 InnoDB Buffer Pool。
- MySQL 8.0 已徹底移除,遷移時務必移除相關配置。
IN() 替代 Join、同表多次自關聯。COUNT(*) 陷阱:InnoDB 無緩存總行數,全表掃描。解決:SELECT COUNT(*) FROM t WHERE id > 0 (走二級索引)、應用層計數表、EXPLAIN 估算行數。LIMIT 1000000, 10 深分頁:改為 WHERE id > last_max_id LIMIT 10 (延遲關聯/子查詢優化)。效能優化無終點,建立「指標導向 → 原理分析 → 驗證閉環」的工程化流程,才是高可用、高吞吐資料庫系統的長期保障。