teamUser:PK (uid, Id)、二級索引 k_id_titleWeight_score (Id, titleWeight, score)、InnoDB。INSERT INTO backup_table SELECT * FROM teamUser (全表掃描)。DELETE FROM teamUser WHERE Id>5 AND titleWeight<32768 AND joinTime<'$daysago_1week' (走二級索引前綴)。lock_rec_lock 確認:InnoDB **逐行獲取鎖** (邊掃描邊加鎖),非一次性獲取。(Id, titleWeight, score) 順序掃描 → **訪問行順序相反**。| 形式 | 場景 | 關鍵條件 |
|---|---|---|
| 1. 兩表交叉鎖 | T1 鎖表 A 行 1 → 鎖表 B 行 2 T2 鎖表 B 行 2 → 鎖表 A 行 1 | 不同表、同行、交叉順序、互斥鎖 |
| 2. 主鍵索引鎖衝突 (本案例) | 同表、不同索引掃描、多行、順序相反 | 同表、不同索引 (PK vs Secondary)、多行、掃描順序不同 |
| 3. 主鍵與二級索引鎖衝突 | T1 用二級索引查找更新 PK T2 用 PK 查找更新 PK | 同行、不同索引、加鎖順序不同 (二級索引先鎖二級再鎖 PK vs PK 先鎖 PK) |
| 4. 鎖升級阻塞 | T1 先得 S 鎖 → 升級 X 鎖 T2 等待 X 鎖 | 同行、S→X 升級、另一事務等 X |
INSERT SELECT 安排低峰獨立時段,避免與寫入衝突;或改用 SELECT INTO OUTFILE + LOAD DATA INFILE (不鎖表、速度更快)。SELECT pk INTO @tmp,再 DELETE ... WHERE pk IN (@tmp),減少掃描範圍與鎖持有時間。ER_LOCK_DEADLOCK (1213),指數退避重試 (建議 3 次),降低業務影響。SHOW ENGINE INNODB STATUS\G 查看最近死鎖詳情 (配合 pager less 閱讀)。innodb_print_all_deadlocks=ON (5.6.2+) 將所有死鎖寫入錯誤日誌。Innodb_deadlocks 計數器 (Prometheus/Grafana 告警)。pt-deadlock-logger 收集分析死鎖模式。