問題:
多個update語句對數據庫做更新操作時,導致數據庫表死鎖。
SQL語句:
語句1:
UPDATE test_table SET col_4_name = '',col_5_name='' WHERE col_1_name = 'xxx' AND col_2_name = 'xxx' AND col_3_name = 'xxx';
語句2:
UPDATE test_table SET col_4_name = '',col_6_name='' WHERE col_1_name = 'xxx' AND col_2_name = 'xxx' AND col_3_name = 'xxx';
死鎖信息如下:
srv_master_thread loops: 2097506 srv_active, 0 srv_shutdown, 7386562 srv_idle
srv_master_thread log flush and writes: 9483563
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 6972941
OS WAIT ARRAY INFO: signal count 10636711
RW-shared spins 0, rounds 15828779, OS waits 5319938
RW-excl spins 0, rounds 55486192, OS waits 447156
RW-sx spins 1788772, rounds 34121454, OS waits 423421
Spin rounds per wait: 15828779.00 RW-shared, 55486192.00 RW-excl, 19.08 RW-sx
------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-12-24 09:46:49 0x7f30a87f4700
*** (1) TRANSACTION:
TRANSACTION 90336432, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 4 row lock(s)
MySQL thread id 14616700, OS thread handle 139847291823872, query id 1166213705 10.99.95.237 test_db updating
UPDATE test_table SET col_4_name = '',col_5_name='' WHERE col_1_name = 'xxx' AND col_2_name = 'xxx' AND col_3_name = 'xxx'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 730 page no 820 n bits 200 index PRIMARY of table `test_db`.`test_table` trx id 90336432 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 13; compact format; info bits 0
0: len 4; hex 80000002; asc ;;
1: len 1; hex 30; asc 0;;
2: len 3; hex 8fbe4e; asc N;;
3: len 4; hex 800003e9; asc ;;
4: len 4; hex 80000001; asc ;;
5: len 30; hex 2f686f6d652f66756e642f6e66732f76612f322f5b4143434f554e545f42; asc /home/fund/nfs/va/2/[ACCOUNT_B; (total 60 bytes);
6: len 6; hex 000002c9141c; asc ;;
7: len 7; hex cd0000018f0110; asc ;;
8: len 4; hex 80000005; asc ;;
9: len 30; hex e69687e4bbb6e78ab6e680815b534a5358582e6462665de69caae590afe7; asc [SJSXX.dbf] ; (total 33 bytes);
10: len 0; hex ; asc ;;
11: len 6; hex 5dd6432c07a8; asc ] C, ;;
12: len 6; hex 5dd6432c07a8; asc ] C, ;;
*** (2) TRANSACTION:
TRANSACTION 90336428, ACTIVE 0 sec fetching rows, thread declared inside InnoDB 4740
mysql tables in use 1, locked 1
431 lock struct(s), heap size 57552, 40698 row lock(s), undo log entries 1
MySQL thread id 14616699, OS thread handle 139846962071296, query id 1166213608 10.99.95.237 test_db updating
UPDATE test_table SET col_4_name = '',col_5_name='' WHERE col_1_name = 'xxx' AND col_2_name = 'xxx' AND col_3_name = 'xxx'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 730 page no 820 n bits 200 index PRIMARY of table `test_db`.`test_table` trx id 90336428 lock_mode X
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;
查找問題步驟:
1.查詢死鎖信息:
(1).執行sql:
show engine innodb status;
(2).查詢結果:如下圖,status中的信息就是死鎖信息,將其內容複製出來分析;
2.分析上一步中查詢到的死鎖信息,找到產生死鎖的sql語句:
2.查看執行計劃:
(2.1).SQl語句:
EXPLAIN UPDATE test_table SET col_4_name = '',col_5_name='' WHERE col_1_name = 'xxx' AND col_2_name = 'xxx' AND col_3_name = 'xxx';
(2.2).分析執行計劃:type爲range,rows爲若干條數據,需要優化。
解決方案:本質是破壞死鎖產生的必要條件
此案例解決方案一:加索引,適合於主鍵爲複合主鍵
1.SQL語句
ALTER TABLE test_table ADD INDEX idx_test_table(col_1_name,col_2_name,col_3_name);
2.注意點:索引的中的字段順序要與update語句後面的條件一致,可不包含所有條件字段,可視情況而定;
此案例解決方案二:先select查詢所要更新的語句,然後根據主鍵更新,適合於主鍵爲唯一主鍵
1.SQL語句
// 查詢
SELECT xxx FROM test_table WHERE col_1_name = 'xxx' AND col_2_name = 'xxx' AND col_3_name = 'xxx';
// 更新對應的記錄
UPDATE test_table SET col_4_name = '',col_5_name='' WHERE XXX ='XXX';
原因:
1.此示例原因:主鍵爲複合主鍵時,主鍵的順序和執行語句後面的條件順序不一致,導致踩了部分索引,使大量數據被鎖定,其他語句執行時,導致死鎖。
2.官方解釋:1. 互斥條件;2. 請求和保持條件;3. 不剝奪條件;4. 循環等待條件。
相關知識點:
1.數據庫索引相關知識;
2.數據庫鎖機制,產生的原因,解決方法等;
代碼示例:
如上。