Note:
engine = innodb (mysql)
tx_isolation = Read-Committed
create table sql:
CREATE TABLE `table_test` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`to_uid` varchar(16) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP,
`to_sid` varchar(100) DEFAULT NULL,
`session_id` varchar(16) DEFAULT NULL ,
PRIMARY KEY (`id`),
UNIQUE KEY `to_uid_to_sid` (`to_uid`,`to_sid`) ,
KEY `idx_uid_time` (`to_uid`,`time`) ,
KEY `idx_uId_session` (`to_uid`,`session_id`,`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
When execute delete statements concurrently ,the unique index to_uid_to_sid and index to_uid_time are both used, the sql is:
DELETE FROM table_test WHERE to_uid='111222' and to_sid in ('xxx','yyyy')
But find deadLock!
DeadLock log is:
------------------------
LATEST DETECTED DEADLOCK
------------------------
2021-08-02 17:54:26 2b075b19b700
*** (1) TRANSACTION:
TRANSACTION 41417931055, ACTIVE 0.000 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 6 lock struct(s), heap size 1184, 6 row lock(s), undo log entries 2
LOCK BLOCKING MySQL thread id: 13894454 block 13894734
MySQL thread id 13894734, OS thread handle 0x2b0b48bc0700, query id 86568609815 172.16.10.213 m_user updating
DELETE FROM table_test WHERE to_uid='111222' and to_sid in ('411-91fb-418f-ae2d-f0a48bb767aa', 'ffa-a04d-4a80-b969-43e068c366ed', '655-f2cc-4198-bf65-c918995877c3')
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1334 page no 647280 n bits 96 index `PRIMARY` of table `chat`.`table_test` trx id 41417931055 lock_mode X locks rec but not gap waiting
Record lock, heap no 5 PHYSICAL RECORD: n_fields 10; compact format; info bits 32
0: len 8; hex 8000000007df89ec; asc ;;
1: len 6; hex 0009a4b37930; asc y0;;
2: len 7; hex 5800003a4623ae; asc X :F# ;;
3: len 9; hex 313439383233353735; asc 149823575;;
4: len 30; hex 7b2276223a312c22736964223a2238303436653739652d623165302d3461; (total 338 bytes);
5: len 4; hex 80000000; asc ;;
6: len 4; hex 6107c06c; asc a l;;
*** (2) TRANSACTION:
TRANSACTION 41417931056, ACTIVE 0.000 sec updating or deleting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1184, 3 row lock(s), undo log entries 1
MySQL thread id 13894454, OS thread handle 0x2b075b19b700, query id 86568609816 172.16.10.213 dml_user updating
DELETE FROM table_test WHERE to_uid='111222' and to_sid in ('79e-b1e0-4afa-86c9-627cf1476209')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS sp ace id 1334 page no 647280 n bits 96 index `PRIMARY` of table `chat`.`table_test` trx id 41417931056 lock_mode X locks rec but not gap
Record lock, heap no 5 PHYSICAL RECORD: n_fields 10; compact format; info bits 32
0: len 8; hex 8000000007df89ec; asc ;;
1: len 6; hex 0009a4b37930; asc y0;;
2: len 7; hex 5800003a4623ae; asc X :F# ;;
3: len 9; hex 313439383233353735; asc 149823575;;
4: len 30; hex 7b2276223a312c22736964223a223830343665373965223165302d3461; asc ; (total 338 bytes);
5: len 4; hex 80000000; asc ;;
6: len 4; hex 6107c06c; asc a l;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1334 page no 474871 n bits 440 index `idx_uid_time` of table `chat`.`table_test` trx id 41417931056 lock_mode X locks rec but not gap waiting
Record lock, heap no 364 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 9; hex 313439383233353735; asc 149823575;;
1: len 4; hex 6107c06c; asc a l;;
2: len 8; hex 8000000007df89ec; asc ;;
*** WE ROLL BACK TRANSACTION (2)
------------
TRANSACTIONS
------------
Not all deadlocks are preventable. Your client should check for such and replay the transaction in the case of a deadlock or a lock_wait_timeout.
What was the logic behind using READ_COMMITTED?
Was there anything other than the DELETE in each of the competing transactions?
I cannot explain this particular deadlock.
Some possible improvements...
Some of the items below are aimed at performance. One way to partially avoid deadlocks is to speed up the queries, thereby getting them finished faster, thereby more often avoiding conflicts.
You have two UNIQUE keys on that table. This leads to extra work and extra chances for deadlocks. Is id used in any other way (such as an FK from another table)? If not, get rid of it.
I would consider replacing all 4 indexes by this one:
PRIMARY KEY(`to_uid`,`to_sid`)
I don't think the other two secondary keys would buy much now that to_uid is the start of the PK, so I tossed them. What is the cardinality of to_uid?
'79e-b1e0-4afa-86c9-627cf1476209' looks like a UUID. If they are all that form, then VARCHAR(100) is overkill; CHAR(36) suffices. (However, that won't improve anything.) Converting to BINARY(16) would provide a significant shrinkage -- which might help performance some.
You have to_uid varchar(16), but the example looks like a number. If that is always numeric, then a numeric datatype would be slightly better (and smaller).
Related
I have a table defined in this way:
CREATE TABLE `measure` (
`measureId` bigint NOT NULL,
`sensorId` int NOT NULL,
`timestamp` bigint NOT NULL,
`data` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
ALTER TABLE `measure`
ADD PRIMARY KEY (`measureId`),
ADD KEY `measure_index` (`sensorId`,`timestamp`);
ALTER TABLE `measure`
MODIFY `measureId` bigint NOT NULL AUTO_INCREMENT;
measureId is mostly used as auto increment, but sometimes I need to specify measureId during insert. I use the following transaction for my application:
begin;
select max(measureId) from measure for update;
-- use the max id retrieved to create measurements
insert into measure values (max_id + 1, ...), (max_id + 2, ...), ...;
-- do other stuff
commit;
I use select ... for update to avoid insertions between selecting max(measureId) and and adding the new rows. Without using it, the transaction would fail since the id would be already taken via autoincrement (I use the default isolation REPEATABLE READS).
In a non concurrent environment the transaction succeeds, but I get a deadlock when this happens between two transactions:
T1: select max(measureId) ...;
T2: select max(measureId) ...; -- starts waiting
T1: into measure values (max_id + 1, ...), ...;
-- ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Why should this be a dealock? T1 should already have the lock on the primary key index (link).
How can i fix this?
Edit: Added output of the innodb status monitor, not sure what is happening. I seems to me that transaction 2 (below) is waiting for a lock it already has.
------------------------
LATEST DETECTED DEADLOCK
------------------------
2023-01-23 13:58:10 139850373236480
*** (1) TRANSACTION:
TRANSACTION 41530, ACTIVE 62 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 2 row lock(s)
MySQL thread id 1251, OS thread handle 139850310264576, query id 5030779 172.19.0.1 root optimizing
select max(measureId) from measure for update
*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 177 page no 22722 n bits 360 index PRIMARY of table `WEATHER_STATION`.`measure` trx id 41530 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) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 177 page no 22722 n bits 360 index PRIMARY of table `WEATHER_STATION`.`measure` trx id 41530 lock_mode X waiting
Record lock, heap no 290 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 80000000004aa795; asc J ;;
1: len 6; hex 00000000a1f8; asc ;;
2: len 7; hex 82000000a913e6; asc ;;
3: len 4; hex 80000192; asc ;;
4: len 8; hex 8000000063cac0ed; asc c ;;
5: len 4; hex 6666ea41; asc ff A;;
*** (2) TRANSACTION:
TRANSACTION 41529, ACTIVE 163 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1128, 3 row lock(s)
MySQL thread id 1250, OS thread handle 139850312378112, query id 5030780 172.19.0.1 root update
insert into measure values (4892566, 1, 2, 3)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 177 page no 22722 n bits 360 index PRIMARY of table `WEATHER_STATION`.`measure` trx id 41529 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;;
Record lock, heap no 290 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 80000000004aa795; asc J ;;
1: len 6; hex 00000000a1f8; asc ;;
2: len 7; hex 82000000a913e6; asc ;;
3: len 4; hex 80000192; asc ;;
4: len 8; hex 8000000063cac0ed; asc c ;;
5: len 4; hex 6666ea41; asc ff A;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 177 page no 22722 n bits 360 index PRIMARY of table `WEATHER_STATION`.`measure` trx id 41529 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** WE ROLL BACK TRANSACTION (2)
Instead, get rid of measureid:
CREATE TABLE `measure` (
`sensorId` int NOT NULL,
`timestamp` bigint NOT NULL,
`data` float NOT NULL,
PRIMARY KEY(sensorId, timestamp)
) ENGINE=InnoDB
Consider using the TIMESTAMP(n) datatype, where n is the number of decimal places (fraction of a second). The max is 6 (microseconds). This will give you a variety of date/time functions that will probably be clearer than futzing with a BIGINT.
Suggest shrinking sensorId to a smaller datatype. For example, SMALLINT UNSIGNED would allow 65K sensors in a 2-byte column.
With those changes, the table (data+indexes) will take about half the disk space. This will have a favorable impact on speed.
With that, you won't need the SELECT (another speedup). And you can possibly do nothing more than the multi-row INSERT.
There are tow transaction,transaction 1 holds an S lock on a row,transaction 2 wants to update the row,then transaction 2 waits,then transaction 1 also performs an updates on the row,at this time a deadlock occurs,I think Know what the reason is ? what is the lock situation here?
I did the following test on mysql5.6 version.There is a deadlock.
Table Stracture:
CREATE TABLE `test` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增',
`uni_id` bigint(20) DEFAULT NULL,
`current_status` int(11) DEFAULT '0' ,
`total` int(11) NOT NULL DEFAULT '0' ,
PRIMARY KEY (`id`),
UNIQUE KEY `uni_id_unique` (`uni_id`),
KEY `uni_id_idx` (`uni_id`),
KEY `current_status_idx` (`current_status`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
init data:
INSERT INTO `test`(`id`, `uni_id`, `current_status`, `total`) VALUES (1, 1, 0, 1);
The following operations are performed in order:
1. first step
Transaction 1 :
start transaction;
select * from test where id=1 lock in share mode;
second step
start transaction;
update test set uni_id=1,total=total+1 where uni_id=1;
third step
Transaction 1:
update test set current_status=1 where id=1 and
current_status=0;
then the dealock happened.
first step : transaction 1 holds S lock.
second step: transaction 2 waits, and from the results of the source code debug,the obtained lock failed.
third step: deadlock
the deadlock info :
*** (1) TRANSACTION:
TRANSACTION 4360, ACTIVE 14 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 376, 2 row lock(s)
MySQL thread id 2, OS thread handle 0x70000a7f4000, query id 145 localhost 127.0.0.1 root updating
update test set uni_id=1,total=total+1 where uni_id=1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 4 page no 3 n bits 72 index `PRIMARY` of table `test`.`test` trx id 4360 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000001106; asc ;;
2: len 7; hex 83000001360110; asc 6 ;;
3: len 8; hex 8000000000000001; asc ;;
4: len 4; hex 80000000; asc ;;
5: len 4; hex 80000001; asc ;;
*** (2) TRANSACTION:
TRANSACTION 4359, ACTIVE 24 sec starting index read
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1248, 2 row lock(s)
MySQL thread id 1, OS thread handle 0x70000a7b0000, query id 149 localhost 127.0.0.1 root updating
update test set current_status=1 where id=1 and
current_status=0
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 4 page no 3 n bits 72 index `PRIMARY` of table `test`.`test` trx id 4359 lock mode S locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000001106; asc ;;
2: len 7; hex 83000001360110; asc 6 ;;
3: len 8; hex 8000000000000001; asc ;;
4: len 4; hex 80000000; asc ;;
5: len 4; hex 80000001; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 4 page no 3 n bits 72 index `PRIMARY` of table `test`.`test` trx id 4359 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000001106; asc ;;
2: len 7; hex 83000001360110; asc 6 ;;
3: len 8; hex 8000000000000001; asc ;;
4: len 4; hex 80000000; asc ;;
5: len 4; hex 80000001; asc ;;
*** WE ROLL BACK TRANSACTION (1)
I don't believe that your analysis of what actually happened is completely correct. This is the likely version of events:
First transaction gets an S lock on the record
Second transaction wants to get an exclusive lock on the same record, but can't, because the first transaction holds the S lock. This transaction therefore waits, trying to obtain the lock.
The third transaction also goes into a wait state on the same record, but now a deadlock happens.
From the MySQL documentation:
Here, FOR SHARE is not a good solution because if two users read the counter at the same time, at least one of them ends up in deadlock when it attempts to update the counter.
As that documentation suggests, a better approach might be to do a SELECT ... FOR UPDATE:
SELECT * FROM test WHERE id = 1 FOR UPDATE;
UPDATE test SET uni_id = 1, total = total+1 WHERE uni_id = 1;
A Friend of mine explained this situation.
From the MYSQL documentation:
Deadlock occurs here because client A needs an X lock to delete the row. However, that lock request cannot be granted because client B already has a request for an X lock and is waiting for client A to release its S lock. Nor can the S lock held by A be upgraded to an X lock because of the prior request by B for an X lock. As a result, InnoDB generates an error for one of the clients and releases its locks
mysql/innodb, repeatable read transaction, deadlock on deletion of non intercepting rows. Trying to understand what is happening.
------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-05-08 06:16:23 7f4a5769a700
*** (1) TRANSACTION:
TRANSACTION 12314813, ACTIVE 1 sec fetching rows
mysql tables in use 1, locked 1
LOCK WAIT 13 lock struct(s), heap size 2936, 355 row lock(s), undo log entries 110
MySQL thread id 1654182, OS thread handle 0x7f4a57658700, query id 21892885 xx.xx.xx.xx oc5z updating
DELETE FROM deal_product_rows_tmp WHERE batch_no=5754
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 219 page no 3 n bits 168 index `PRIMARY` of table `db1`.`deal_product_rows_tmp` trx id 12314813 lock_mode X waiting
Record lock, heap no 88 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
0: len 4; hex 80001bb9; asc ;;
1: len 6; hex 000000bbe8c0; asc ;;
2: len 7; hex be000001b50110; asc ;;
3: len 4; hex 8000167b; asc {;;
4: len 4; hex 800fe7c4; asc ;;
5: len 4; hex 80002516; asc % ;;
6: len 4; hex 8000986e; asc n;;
7: len 4; hex 80000003; asc ;;
8: len 30; hex 415254455820d184d0bed180d0bcd18b20d0bfd180d18fd0bcd0bed183d0; asc PROD ; (total 81 bytes);
9: len 8; hex 0000000000208c40; asc #;;
10: len 1; hex 4d; asc M;;
*** (2) TRANSACTION:
TRANSACTION 12314816, ACTIVE 1 sec starting index read
mysql tables in use 1, locked 1
14 lock struct(s), heap size 2936, 95 row lock(s), undo log entries 14
MySQL thread id 1654175, OS thread handle 0x7f4a5769a700, query id 21892888 xx.xx.xx.xx oc5z updating
DELETE FROM deal_product_rows_tmp WHERE batch_no=5755
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 219 page no 3 n bits 168 index `PRIMARY` of table `db1`.`deal_product_rows_tmp` trx id 12314816 lock_mode X locks rec but not gap
Record lock, heap no 25 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
Table structure:
CREATE TABLE `deal_product_rows_tmp` (
`batch_no` int(11) NOT NULL,
`bitrix_id` int(11) NOT NULL,
`deal_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
`quantity` int(11) NOT NULL,
`product_name` varchar(1000) NOT NULL,
`price` double DEFAULT NULL,
`status` varchar(50) NOT NULL,
`tmp_id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`tmp_id`),
KEY `idx_deal_row_tmp_deal` (`deal_id`),
KEY `idx_deal_row_tmp_batchno` (`batch_no`)
) ENGINE=InnoDB AUTO_INCREMENT=7500 DEFAULT CHARSET=utf8
Did I understand correctly: first transaction trying to apply gap lock on all rows at index page. one by one record (Next-Key Locks). Second transaction trying the same, but in different direction. In result part of index page locked by transaction 1, part by transaction 2.
I'm understand that I can reduce transaction isolation level to RC, I'm trying to understand how the repeatable read works in innodb.
UPDATE: same situation with Read Committed IL.
I have a simple table with:
deviceid
pushid
tag
external_id
When sending messages to the users, we sometimes do an update of the pushid based on the deviceid:
update user_notifications set pushid='xyz' where deviceid='abc'
But at the same time we can get a new registration from the user where we reset all his notifications with
delete from user_notifications where pushid='xyz' and external_id is null
This seems to trigger deadlocks regularly. I have added indexes on "deviceid" and "pushid, external_id" but it seems to still trigger a deadlock. The table have no suitable primary key so MySQL have created a GEN_CLUST_INDEX key. Can this be the reason? Should I add an auto-incrementing primary key?
------------------------
LATEST DETECTED DEADLOCK
------------------------
141014 8:13:38
*** (1) TRANSACTION:
TRANSACTION F5ED32, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1248, 2 row lock(s)
MySQL thread id 2422, OS thread handle 0x7f6295cd3700, query id 35096 localhost root Updating
update user_notifications set pushid='APA91bEO5zBhpAqiNlHIlWvvb0U4KH2JWByzh5IzmJFg2GZyXX2s1wJ2pbTHWoTDDao5hoZ10e1bw70Z5nTi4dIEfsTj6q-cS9U0VuqwGkWpW4ofb4XnbjOd39845_jXsPaiFg5EmD0Y9JSd3rP3BY-M8ZQEet1So6SBOgSLdjlV5MtxYyR5kos' where deviceid='64881a83-c43b-4282-b82f-2a136395e3c6'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 143022 n bits 128 index `GEN_CLUST_INDEX` of table `myappdb`.`user_notifications` trx id F5ED32 lock_mode X locks rec but not gap waiting
Record lock, heap no 55 PHYSICAL RECORD: n_fields 7; compact format; info bits 32
0: len 6; hex 0000003315f7; asc 3 ;;
1: len 6; hex 000000f5ed31; asc 1;;
2: len 7; hex 63000c40180110; asc c # ;;
3: len 30; hex 36343838316138332d633433622d343238322d623832662d326131333633; asc 64881a83-c43b-4282-b82f-2a1363; (total 36 bytes);
4: len 30; hex 415041393162454f357a4268704171694e6c48496c577676623055344b48; asc APA91bEO5zBhpAqiNlHIlWvvb0U4KH; (total 183 bytes);
5: len 9; hex 7465616d5f39383233; asc team_9823;;
6: SQL NULL;
*** (2) TRANSACTION:
TRANSACTION F5ED31, ACTIVE 0 sec updating or deleting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1248, 3 row lock(s), undo log entries 1
MySQL thread id 2423, OS thread handle 0x7f6295c92700, query id 35104 localhost root updating
delete from user_notifications where pushid='APA91bEO5zBhpAqiNlHIlWvvb0U4KH2JWByzh5IzmJFg2GZyXX2s1wJ2pbTHWoTDDao5hoZ10e1bw70Z5nTi4dIEfsTj6q-cS9U0VuqwGkWpW4ofb4XnbjOd39845_jXsPaiFg5EmD0Y9JSd3rP3BY-M8ZQEet1So6SBOgSLdjlV5MtxYyR5kos' and external_id is null
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 143022 n bits 128 index `GEN_CLUST_INDEX` of table `myappdb`.`user_notifications` trx id F5ED31 lock_mode X locks rec but not gap
Record lock, heap no 55 PHYSICAL RECORD: n_fields 7; compact format; info bits 32
0: len 6; hex 0000003315f7; asc 3 ;;
1: len 6; hex 000000f5ed31; asc 1;;
2: len 7; hex 63000c40180110; asc c # ;;
3: len 30; hex 36343838316138332d633433622d343238322d623832662d326131333633; asc 64881a83-c43b-4282-b82f-2a1363; (total 36 bytes);
4: len 30; hex 415041393162454f357a4268704171694e6c48496c577676623055344b48; asc APA91bEO5zBhpAqiNlHIlWvvb0U4KH; (total 183 bytes);
5: len 9; hex 7465616d5f39383233; asc team_9823;;
6: SQL NULL;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 68396 n bits 232 index `index3` of table `myappdb`.`user_notifications` trx id F5ED31 lock_mode X locks rec but not gap waiting
Record lock, heap no 97 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 30; hex 36343838316138332d633433622d343238322d623832662d326131333633; asc 64881a83-c43b-4282-b82f-2a1363; (total 36 bytes);
1: len 6; hex 0000003315f7; asc 3 ;;
*** WE ROLL BACK TRANSACTION (1)
As you said and the log shows, updating the 'pushid' value and deleting the row is happening at same time. This should be easy to avoid. For some official tips, take a look at MySQL 'How to Cope with Deadlocks" document: http://dev.mysql.com/doc/refman/5.5/en/innodb-deadlocks.html
My question is this: Why does transaction 1 hold the primary lock and why does transaction 2 need primary lock? I can't find any information about this lock in mysql manual.
Information about this deadlock:
transaction 1:
1988266681 Query BEGIN
1988266681 Query INSERT IGNORE INTO `tab1`
(`sn`, `is_fetch`, `is_done`, `add_time`)
VALUES ('4287', 0, 0, 1403186277)
1988266681 Query COMMIT
transaction 2:
1988212988 Query BEGIN
1988212988 Query SELECT sn FROM tab1 WHERE is_fetch = 0
LIMIT 200 FOR UPDATE
1988212988 Query UPDATE `tab1` SET `is_fetch` = 1
WHERE sn in ('4287', '4387', '4487', '4587', '4687',
'4787', '4887', '4987')
1988212988 Query COMMIT
schema info:
CREATE TABLE `tab1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sn` varchar(20) NOT NULL,
`is_fetch` tinyint(1) NOT NULL DEFAULT '0' ,
`is_done` tinyint(1) NOT NULL DEFAULT '0' ,
`add_time` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `sn` (`sn`),
KEY `is_fetch` (`is_fetch`),
KEY `is_done` (`is_done`)
) ENGINE=InnoDB AUTO_INCREMENT=4387619 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
deadlock info:
------------------------
LATEST DETECTED DEADLOCK
------------------------
140617 23:25:36
*** (1) TRANSACTION:
TRANSACTION 36E4099DA, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 1937033606, OS thread handle 0x2ae3b0040700, query id 18031163883 192.168.1.65 db1 update
INSERT IGNORE INTO `tab1` (`sn`, `is_fetch`, `is_done`, `add_time`) VALUES ('1887', 0, 0, 1403018736)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 625 page no 5 n bits 1616 index `is_fetch` of table `db1`.`tab1` trx id 36E4099DA lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 1476 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 1; hex 81; asc ;;
1: len 4; hex 80410669; asc A i;;
*** (2) TRANSACTION:
TRANSACTION 36E4099D7, ACTIVE 0 sec fetching rows, thread declared inside InnoDB 458
mysql tables in use 1, locked 1
6 lock struct(s), heap size 3112, 51 row lock(s), undo log entries 7
MySQL thread id 1937007092, OS thread handle 0x2ae8b5a26700, query id 18031163880 192.168.1.130 db1 Updating
UPDATE `tab1` SET `is_fetch` = 1 WHERE sn in ('1187', '1287', '1387', '1487', '1587', '1687', '1787')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 625 page no 5 n bits 1616 index `is_fetch` of table `db1`.`tab1` trx id 36E4099D7 lock_mode X locks gap before rec
Record lock, heap no 1476 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 1; hex 81; asc ;;
1: len 4; hex 80410669; asc A i;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 625 page no 3 n bits 440 index `PRIMARY` of table `db1`.`tab1` trx id 36E4099D7 lock_mode X waiting
Record lock, heap no 168 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 4; hex 80411598; asc A ;;
1: len 6; hex 00036e4099da; asc n# ;;
2: len 7; hex e80000c0060110; asc ;;
3: len 14; hex 3134303631373338343331383837; asc 1887;;
4: len 1; hex 80; asc ;;
5: len 1; hex 80; asc ;;
6: len 4; hex d3a05df0; asc ] ;;
Q: How did this happen?
Transaction 2 obtained an exclusive lock on records in the 'is_fetch` index, and attempted to obtain a lock on records in the PRIMARY key of the table.
Transaction 1 obtained an exclusive lock on records in the PRIMARY key of the table, and attempted to obtain a lock on records in the is_fetch index.
InnoDB automatically detects that neither transaction can proceed, because each is holding resources needed by the other. InnoDB terminates one of the transactions so the other transaction can proceed.
Note that an INSERT statement can obtain a "gaps" lock for records in unique indexes. It's not just INSERT that caused the deadlock, it was the combination of transactions that were running concurrently.
InnoDB record locking is documented in the MySQL Reference manual here:
http://dev.mysql.com/doc/refman/5.5/en/innodb-record-level-locks.html
SELECT ... FOR UPDATE acquire lock for scanned rows. You can reed more here: http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html and here http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html