MySQL 的查詢與更新速度直接決定了應用程式的響應能力。本文系統梳理影響效能的關鍵因素,並提供從權限檢查、索引設計、查詢優化到具體操作(SELECT、INSERT、UPDATE、DELETE)的調優實戰指南。
MySQL 的權限檢查會帶來額外開銷。權限系統越複雜(GRANT 語句越多),每次查詢的權限驗證成本越高。若應用不需要精細權限控制,可避免使用 GRANT,或簡化權限結構,以減少每次查詢的權限檢查開銷。
內建函數 BENCHMARK(loop_count, expression) 可快速評估表達式執行效率。例如在 Pentium II 400MHz 上執行 1,000,000 次 1+1 僅耗時 0.32 秒。所有內建函數均經高度優化,但仍可能存在例外,遇到疑似函數瓶頸時可用此工具驗證。
對於小表,索引通常被緩衝,僅需 1 次磁盤尋道即可定位行。大表使用 B+ 樹索引時,尋道次數估算公式:
log(row_count) / log(index_block_length / 3 * 2 / (index_length + data_pointer_length)) + 1
以 50 萬行、索引長度 3 字節(MEDIUMINT)、索引塊 1024 字節、資料指標 4 字節為例,約需 4 次尋道。索引大小約 5.2 MB,若索引緩衝區命中率高(典型 2/3 滿),實際可能僅需 1-2 次系統調用即可讀取資料。
寫入操作需額外尋道:約 4 次尋道定位新索引位置,加 2 次尋道更新索引並寫入行。隨資料增長,只要作業系統或 MySQL 緩衝池能容納熱點資料,效能衰減緩慢;一旦超出緩衝容量,受磁盤尋道限制,效能將呈 N log N 級下降。解決之道是隨資料增長同步擴大索引緩衝區(參見 key_buffer_size 調整)。
EXPLAIN 分析實際使用的索引。myisamchk --analyze:載入資料後執行,更新索引統計資訊,助優化器做出更好決策。myisamchk --sort-index --sort-records=1 可按索引順序排列資料,加速按索引順序讀取。注意大表排序耗時極長。MySQL 對 WHERE 條件執行多層優化,同樣適用於 DELETE 和 UPDATE:
((a AND b) AND c OR (((a AND b) AND (c AND d)))) → (a AND b AND c) OR (a AND b AND c AND d)(a<b AND b=c) AND a=5 → b>5 AND b=c AND a=5(B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6) → B=5 OR B=6COUNT(*) 直接從表元資料讀取下列情況視為常數表(優先讀取、僅 1 行):
SQL_SMALL_RESULT 使用記憶體臨時表SELECT COUNT(*) FROM tbl_name; SELECT MIN(key_part1), MAX(key_part1) FROM tbl_name; SELECT MAX(key_part2) FROM tbl_name WHERE key_part_1=constant; SELECT ... FROM tbl_name ORDER BY key_part1, key_part2 LIMIT 10; SELECT ... FROM tbl_name ORDER BY key_part1 DESC, key_part2 DESC LIMIT 10;
column_name IS NULL 且該列定義為 NOT NULL,找到首匹配行後停止該鍵組合的進一步搜尋LIMIT # 可能改用索引而非全表掃描LIMIT # ORDER BY:找到前 # 行即停止排序LIMIT # DISTINCT:找到 # 個唯一行即停止LIMIT # 避免不必要分組計算LIMIT 0 快速回傳空集合,適合檢查欄位類型LIMIT # 決定單筆插入耗時組成:連接(3) + 發送查詢(2) + 解析(2) + 插入記錄(1×大小) + 插入索引(1×索引數) + 關閉(1)。表大小以 N log N 減慢索引插入。
FLUSH TABLESmyisamchk --keys-used=0 -rq 禁用索引LOAD DATA INFILE 載入資料(不更新索引)myisampackmyisamchk -r -q 重建索引(記憶體中構建平衡樹,避免大量尋道)FLUSH TABLESLOCK TABLES a WRITE → 多條 INSERT → UNLOCK TABLES,索引緩衝區僅刷盤一次。單條大 INSERT 無需鎖表。鎖表降低整體耗時約 40%,但增加個別線程等待時間。建議每 1000 行 UNLOCK TABLES 釋放並發。UPDATE 被優化為帶寫入開銷的 SELECT。寫入速度取決於更新資料量與被更新索引數。延遲更新、批次鎖表執行比逐行單獨更新更快。動態記錄格式下頻繁更新長記錄可能導致記錄分裂,需定期 OPTIMIZE TABLE 整理。
刪除耗時與索引數成正比。增大索引緩衝區可加速刪除。TRUNCATE TABLE 或 DELETE FROM table(無 WHERE)清空全表比大量逐行刪除快得多。