Deadlock case 7

Source: public account yangyidba

I. Introduction

Deadlock is actually a very interesting and challenging technical problem. Probably every DBA and some development students will encounter it in the course of work. Regarding deadlock, I will continue to write a series of case studies, hoping to help friends who want to understand deadlock.

2. Case analysis

2.1 Business scenario

Business development students want to synchronize data. Their logic is to update through the update operation. If the affect_rows returned by the updated record is 0, then the insert statement is called to initialize the insert . If the insert fails, the update operation is performed again, and a deadlock occurs in the case of concurrent operations of multiple sessions.

2.2 Environmental description

MySQL 5.6.24 transaction isolation level is RR

create table ty (
  id int not null primary key auto_increment ,
  c1 int not null default 0,
  c2 int not null default 0,
  c3 int not null default 0,
  unique key uc1(c1),
  unique key uc2(c2)
) engine=innodb ;
insert into ty(c1,c2,c3)
values(1,3,4),(6,6,10),(9,9,14);

2.3 Test case

2.4 Deadlock log

2018-03-27 17:59:23 0x7f75bf39d700
*** (1) TRANSACTION:
TRANSACTION 1863, ACTIVE 76 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 382150, OS thread handle 56640, query id 28 localhost root update
insert into ty (c1,c2,c3) values(3,4,2)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 28 page no 5 n bits 72 index uc2 of table `test`.`ty` trx id 1863 lock_mode X locks gap before rec insert intention waiting
*** (2) TRANSACTION:
TRANSACTION 1864, ACTIVE 65 sec inserting, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 382125, OS thread handle 40032, query id 62 localhost root update
insert into ty (c1,c2,c3) values(3,4,2)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 28 page no 5 n bits 72 index uc2 of table `test`.`ty` trx id 1864 lock_mode X locks gap before rec
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 28 page no 4 n bits 72 index uc1 of table `test`.`ty` trx id 1864 lock mode S waiting
*** WE ROLL BACK TRANSACTION (2)

2.5 Analyze the deadlock log

First of all, we need to re-emphasize the locking logic of the insert operation.

The first stage: uniqueness constraint check, first apply for  LOCK_S + LOCK_ORDINARY

The second stage: After acquiring the lock of stage 1 and inserting successfully, there is a GAP lock at the inserted position: LOCK_INSERT_INTENTION, in order to prevent other insert unique key conflicts.

After the new data is inserted: LOCK_X + LOCK_REC_NOT_GAP

For the insert operation, if a unique constraint conflict occurs, you need to add S Next-key Lock to the conflicting unique index. From here, you will find that even at the RC transaction isolation level, there will also be a Next-Key Lock lock, thereby blocking concurrency. However, what the document does not say is that for the unique index where the conflict is detected, the waiting thread needs to lock the next record after obtaining the S Lock. The source code is used to determine the function row_ins_scan_sec_index_for_duplicate.

Secondly, we need the unlocked compatibility matrix.

From the compatibility matrix, we can draw the following conclusions:

There will be no conflicts between INSERT operations.

GAP, Next-Key will block Insert.

GAP and Record, Next-Key will not conflict.

Record and Record, Next-Key conflict with each other.

The existing Insert lock does not prevent any locks that are to be added.

GAP locks already held will block the insertion intention lock INSERT_INTENTION.

In addition , GAP locks will be applied for updating or deleting non-existent records through a unique index.

analysis

Understanding the basic knowledge above, we began to analyze the deadlock log:

T1: sess1 updates the data through the unique key. Since c2=4 does not exist, the affect row is returned as 0, and MySQL will apply for the GAP lock between (3,6).

T2: The situation of sess2 is similar to that of sess1, and the GAP lock between (3,6) will also be applied. From the above compatibility matrix, the two GAP locks will not conflict.

T3: sess1 returns affect row as 0 according to the update statement and executes the insert operation. At this time, it is necessary to apply for an insert intention lock. The GAP lock held by the sess2 session conflicts with the insert intention lock applied for by sess1, and there is a wait.

index uc2 of table test.ty trx id 1863 lock_mode X locks gap before rec insert intention waiting

T4: sess2 is similar to sess1. According to the update statement, the affect row is returned as 0, and the insert operation is executed. The applied insertion intention lock conflicts with the GAP lock held by the update statement of sess1. sess1 (holding GAP lock), sess2 (holding GAP lock), sess1 (insertion intention lock waiting for sess2's GAP lock release) sess2 (insertion intention lock waiting for sess1's GAP lock release)  constitute a circular wait, which leads to deadlock.

2.6 Solution

From the perspective of the processing logic of the business scenario, the business needs to send two requests, one update, and one insert to complete the business logic, which is not friendly and optimized.

In fact, we can communicate well with the development classmates to confirm the idempotence of the business, use the insert on duplicate key method, insert if there is no, update if it exists, one call can complete the function of the previous two operations, and improve performance.

Three, summary

Finally, I want to talk about the idea of ​​solving the deadlock problem:

1. Have a solid basic knowledge of locks.

2. It is difficult to judge the specific SQL execution situation based on the deadlock log alone. It is necessary to communicate with the development classmates to clarify the business execution SQL logic, and then to simulate the test.

Extended reading

The full text is over.

Enjoy MySQL :)

Teacher Ye's "MySQL Core Optimization" class has been upgraded to MySQL 8.0, scan the code to start the journey of MySQL 8.0 practice

Guess you like

Origin blog.csdn.net/n88Lpo/article/details/108924174