MySQL – How to Prevent Deadlock on Concurrent Inserts

deadlockMySQLpercona

Percona Server 5.6.39-83.1-log

Table structure:

CREATE TABLE `myTable` (
    `column_1` VARCHAR(50) NOT NULL DEFAULT '',
    `column_2` VARCHAR(50) NOT NULL DEFAULT '',
    `column_3` VARCHAR(50) NOT NULL DEFAULT '',
    `column_4` VARCHAR(50) NOT NULL DEFAULT '',
    `column_5` VARCHAR(50) NOT NULL DEFAULT '',
    PRIMARY KEY (`column_1`, `column_2`, `column_3`) USING BTREE,
    INDEX `column_3` (`column_3`) USING BTREE,
    INDEX `column_4_5` (`column_4`, `column_5`) USING BTREE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

There are two or more concurrent insert leads to deadlock:

------------------------
LATEST DETECTED DEADLOCK
------------------------
2020-03-23 18:12:45 7f1c08eb8700
*** (1) TRANSACTION:
TRANSACTION 55665288601, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1184, 2 row lock(s)
MySQL thread id 10275055, OS thread handle 0x7f1c08c6c700, query id 56392293629 localhost user update
INSERT IGNORE INTO myDB.myTable
(`column_1`, `column_2`, `column_3`, `column_4`, `column_5`)
VALUES
('a1', 'a2', 'a3', 'a4', 'a5'),
('b1', 'b2', 'b3', 'b4', 'b5'),
('c1', 'c2', 'c3', 'c4', 'c5'),
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 337207190 page no 7370 n bits 200 index `PRIMARY` of table `myDB`.`myTable` trx id 55665288601 lock mode S locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 55665288598, ACTIVE 0 sec inserting, thread declared inside InnoDB 4965
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1184, 2 row lock(s), undo log entries 35
MySQL thread id 10275057, OS thread handle 0x7f1c08eb8700, query id 56392293627 localhost user update
INSERT IGNORE INTO myDB.myTable
(`column_1`, `column_2`, `column_3`, `column_4`, `column_5`)
VALUES
('a1', 'a2', 'a3', 'a4', 'a5'),
('b1', 'b2', 'b3', 'b4', 'b5'),
('c1', 'c2', 'c3', 'c4', 'c5')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 337207190 page no 7370 n bits 200 index `PRIMARY` of table `myDB`.`myTable` trx id 55665288598 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 337207190 page no 83133 n bits 144 index `PRIMARY` of table `myDB`.`myTable` trx id 55665288598 lock_mode X insert intention waiting
*** WE ROLL BACK TRANSACTION (1)

Why is this happening?
Despite the fact that I do not use auto-increment in the primary key and use IGNORE in query.
How should I avoid this problem?

Best Answer

Both insert statements have the same values for the primary key which is why the deadlock occurred.

At the point of the deadlock, the other transaction could rollback. If the INSERT IGNORE did ignore, and the other transaction rolled back, then the definition of 'INSERT IGNORE' inserting if a record doesn't exist is violated.

This is why the deadlock is returned, because its a business logic problem that needs to be resolved by the application. The action to be taken in a deadlock depends on the situation that cannot be known upfront.