理解 MySQL 鎖機制是高併發優化的前提。本文系統講解三級鎖(行級、頁級、表級)特性對比、MyISAM 表鎖模式與爭用分析、並發插入控制、鎖調度優先級調整,並提出讀寫分離作為根治高併發鎖爭用的架構方案。
| 鎖級別 | 存儲引擎 | 開銷 | 加鎖速度 | 死鎖 | 鎖粒度 | 衝突概率 | 併發度 |
|---|---|---|---|---|---|---|---|
| 行級鎖 | InnoDB | 大 | 慢 | 會發生 | 最小 | 最低 | 最高 |
| 頁級鎖 | BDB | 中 | 中 | 會發生 | 中 | 中 | 中 |
| 表級鎖 | MyISAM, MEMORY | 小 | 快 | 不發生 | 最大 | 最高 | 最低 |
SELECT 前自動加。不阻塞其他讀,阻塞寫。INSERT/UPDATE/DELETE 前自動加。阻塞所有其他讀寫。
SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name | Value |
+-----------------------+---------+
| Table_locks_immediate | 76939364 |
| Table_locks_waited | 305089 |
+-----------------------+---------+
Table_locks_waited 較高(此例 30 萬+)說明存在嚴重表鎖爭用。
-- 客戶端 1:長時間讀操作(3 分 15 秒)
SELECT COUNT(*) FROM gz_phone GROUP BY ua;
-- 客戶端 2:並發讀 → 立即返回(0.01s)
SELECT id, phone FROM gz_phone LIMIT 1000, 10;
-- 客戶端 2:並發寫 → 等待 2 分 57 秒(讀鎖釋放後執行)
UPDATE gz_phone SET phone='11111111111' WHERE id=1001;
-- 客戶端 1:長時間寫操作(3 分 4 秒)
UPDATE gz_phone SET phone='11111111111';
-- 客戶端 2:並發讀 → 等待 2 分 58 秒
SELECT * FROM gz_phone LIMIT 10;
-- 客戶端 3:並發寫 → 等待 3 分 50 秒
UPDATE gz_phone SET phone='55555' WHERE id=1;
結論:寫鎖獨佔,讀寫互斥,長查詢/長事務會嚴重阻塞併發。
系統變量 concurrent_insert 控制:
| 值 | 行為 |
|---|---|
| 0 | 禁用並發插入 |
| 1 (默認) | 表無空洞(無刪除/更新導致碎片)時,讀鎖下允許尾部插入 |
| 2 | 無論是否有空洞,均允許尾部並發插入 |
建議:純追加寫入場景(日誌、埋點)設 2 可提升併發;有刪除更新的表謹慎使用。
默認寫優先:寫請求插隊到讀請求前面。大量更新導致查詢「餓死」。
--low-priority-updates → 讀優先SET LOW_PRIORITY_UPDATES=1INSERT/UPDATE/DELETE LOW_PRIORITY ...缺點:長查詢會導致寫入餓死。無法同時滿足讀寫低延遲。
架構層面解決鎖爭用:
SELECT ... LOCK IN SHARE MODE / FOR UPDATE 濫用Table_locks_waited、Innodb_row_lock_waits、Innodb_row_lock_time_avgOPTIMIZE TABLE 減少碎片,提升並發插入效率鎖是資料庫併發控制的核心。MyISAM 表鎖在高併發寫入場景下是性能瓶頸,InnoDB 行級鎖配合合理索引設計是主流選擇。架構層面,讀寫分離是解決讀寫鎖爭用的終極方案。