Why concurrent "Delete...Insert" statements cause a deadlock? - mysql

Consider the following schema in mysql:
create table foo(
id int not null primary key auto_increment,
name varchar(32) not null,
unique key(name)
);
And there is a record with name "abc" in the table.
I have a transaction (RC):
start transaction;
delete from foo where name = "abc";
insert into foo(name) values("abc");
commit;
If there are two concurrent transactions, the dead lock will happen.
| TX A | TX B
---------------------------------------------------------------------
Step 1 | start transaction; |
| delete name="abc"; |
---------------------------------------------------------------------
Step 2 | | start transaction;
| | delete name="abc";
| | <wait for lock>
---------------------------------------------------------------------
Step 3 | insert name="abc"; | <deadlock detected, exit>
---------------------------------------------------------------------
Step 4 | commit; |
---------------------------------------------------------------------
I'm wondering why this sequence causes the deadlock.
In the mysql doc says (https://dev.mysql.com/doc/refman/8.0/en/innodb-locks-set.html)
If a duplicate-key error occurs, a shared lock on the duplicate index
record is set. This use of a shared lock can result in deadlock should
there be multiple sessions trying to insert the same row if another
session already has an exclusive lock. This can occur if another session
deletes the row.
I suppose when transaction A runs the "delete" statement, it has acquired the X lock of the record "abc". When the "insert" statement executes, it tries to acquire the S lock due to the "duplicate key error". Shouldn't it get the S lock since it has got the X lock of the same record? Why deadlock happens here?

I reproduced the deadlock, and got the innoDB status log as follow:
------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-10-18 18:35:14 0x7f1dfc738700
*** (1) TRANSACTION:
TRANSACTION 26547965, ACTIVE 6 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
/* ApplicationName=DataGrip 2019.1.1 */ delete from foo where name='abc'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3011 page no 4 n bits 224 index IDX_NAME of table `foo` trx id 26547965 lock_mode X locks rec but not gap waiting
Record lock, heap no 153 PHYSICAL RECORD: n_fields 2; ....
*** (2) TRANSACTION:
TRANSACTION 26547960, ACTIVE 10 sec inserting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 2
/* ApplicationName=DataGrip 2019.1.1 */ INSERT INTO foo(id, name)
VALUES (1, 'abc')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 3011 page no 4 n bits 224 index IDX_NAME of table `foo` trx id 26547960 lock_mode X locks rec but not gap
Record lock, heap no 153 PHYSICAL RECORD: ...
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3011 page no 4 n bits 224 index IDX_NAME of table `foo` trx id 26547960 lock mode S waiting
Record lock, heap no 153 PHYSICAL RECORD: ....
*** WE ROLL BACK TRANSACTION (1)
The log explains the reason clearly, TX B waiting X lock held by TX A, at the same time, TX A waiting S lock which is block by TX B's lock request.
According to Mysql doc:
If a duplicate-key error occurs, a shared lock on the duplicate index record is set. This use of a shared lock can result in deadlock should there be multiple sessions trying to insert the same row if another session already has an exclusive lock. "
Insert statement does acquire S lock at some point, so the reason for why deadlock happens is very clear.
But problem is:
according to the mysql doc, insert statement will acquire a S lock if a duplicate-key error occurs, which is not happened in current case we discuss
why insert statement still acquire a S lock when current transaction already holds the X lock, X lock is enough for doing a current read to check the duplicate key error. so what does it use for ?

Related

MySQL: A deadlock occurred when deleting the same row

Recently I encountered a deadlock when deleting records (Note that the isolation level is REPEATABLE READ, MySQL 5.7)
Here is the repro steps
1 Create a new table
CREATE TABLE `t` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`),
KEY `p_name` (`name`)
) ENGINE=InnoDB CHARSET=utf8;
2 Prepare 3 records
insert into t (name) value ('A'), ('C'), ('D');
3
+====================================+============================================================+
| Session A | Session B |
+====================================+============================================================+
| begin; | |
+------------------------------------+------------------------------------------------------------+
| | begin; |
+------------------------------------+------------------------------------------------------------+
| delete from t where name = 'C'; | |
+------------------------------------+------------------------------------------------------------+
| | delete from t where name = 'C'; --Blocked! |
+------------------------------------+------------------------------------------------------------+
| insert into t (name) values ('B'); | |
+------------------------------------+------------------------------------------------------------+
| | ERROR 1213 (40001): Deadlock found when trying to get lock |
+------------------------------------+------------------------------------------------------------+
The result of show engine innodb status as below shown (LATEST DETECTED DEADLOCK section)
LATEST DETECTED DEADLOCK
------------------------
*** (1) TRANSACTION:
TRANSACTION 3631, ACTIVE 21 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 13, OS thread handle 123145439432704, query id 306 localhost root updating
delete from t where name = 'C'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 69 page no 4 n bits 72 index p_name of table `jacky`.`t` trx id 3631 lock_mode X waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 1; hex 43; asc C;;
1: len 8; hex 8000000000000018; asc ;;
*** (2) TRANSACTION:
TRANSACTION 3630, ACTIVE 29 sec inserting
mysql tables in use 1, locked 1
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
MySQL thread id 14, OS thread handle 123145439711232, query id 307 localhost root update
insert into t (name) values ('B')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 69 page no 4 n bits 72 index p_name of table `jacky`.`t` trx id 3630 lock_mode X
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 1; hex 43; asc C;;
1: len 8; hex 8000000000000018; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 69 page no 4 n bits 72 index p_name of table `jacky`.`t` trx id 3630 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 1; hex 43; asc C;;
1: len 8; hex 8000000000000018; asc ;;
As the Innodb status shown, session B is waiting next-key lock C, and session A hold a record lock C and waiting gap lock on C;
As we all know that
DELETE FROM ... WHERE ... sets an exclusive next-key lock on every record the search encounters
A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.
Q1: I guess if session B firstly got the gap lock (part of next-key), and then waiting for the record lock. Thereby, the latter insert in session A was blocked by session B (due to the gap lock), and eventually result in a dead lock. Right?
Q2: As the C is purged from an index, does the gap lock hold by session B should be ('A', 'D')? If so, why the session A is waiting the insert intension lock on range (, 'C')?
Q3: Why session B has 1 row lock(s), and session A has 4 row lock(s)?
Q4: When change index p_name to a unique index, we still get the deadlock due to gap lock, it's weird. It behaves different from official doc which states only record lock is required.
DELETE FROM ... WHERE ... sets an exclusive next-key lock on every record the search encounters. However, only an index record lock is required for statements that lock rows using a unique index to search for a unique row.
However, it is okay when using primary key id to execute delete (steps as below shown). Is this a bug in MySQL?
1 Prepare data
delete from t;
insert into t (id, name) value (1, 'A'), (3, 'C'), (5, 'D');
2
+-------------------------------------------+--------------------------------------+
| Session A | Session B |
+-------------------------------------------+--------------------------------------+
| begin; | |
| | begin; |
| delete from t where id = 3; | |
| | delete from t where id = 3; Blocked! |
| insert into t (id, name) values (2, 'B'); | |
| | |
| commit; | |
+-------------------------------------------+--------------------------------------+
From "WAITING FOR THIS LOCK TO BE GRANTED" part of transaction 3631, we could see:
RECORD LOCKS space id 69 page no 4 n bits 72 index p_name of table `jacky`.`t` trx id 3631 lock_mode X waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
3631 is waiting a record lock. The corresponding index content is {"name":"C", "id": 24}.
The index name is p_name in table t.
lock's mode is "lock_mode X"
From "WAITING FOR THIS LOCK TO BE GRANTED" part of transaction 3630, we could see:
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 69 page no 4 n bits 72 index p_name of table `jacky`.`t` trx id 3630 lock_mode X
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 1; hex 43; asc C;;
1: len 8; hex 8000000000000018; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 69 page no 4 n bits 72 index p_name of table `jacky`.`t` trx id 3630 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 2; compact format; info bits 32
0: len 1; hex 43; asc C;;
1: len 8; hex 8000000000000018; asc ;;
3630 is waiting a record lock. The corresponding index content is {"name":"C", "id": 24}. waiting lock's mode is "lock_mode X locks gap"
3630 is holding a record lock. The corresponding index content is {"name":"C", "id": 24}. Holding lock's mode is "lock_mode X locks"
The index name is p_name in table t.
This deadlock is caused by executing "insert into t (name) values ('B')"
According to your reproduce step, session A will send a delete from t where name = 'C'; first, this will lock:
('A', 'C'] and ('C', 'D'): next-key lock 'C' and gap lock before 'D';
DELETE FROM ... WHERE ... sets an exclusive next-key lock on every
record the search encounters. However, only an index record lock is
required for statements that lock rows using a unique index to search
for a unique row.
add a record lock for 'C' corresponding primary index id. here id value should be "26".
Then session B will start and delete from t where name = 'C'; will be executed again. However. For session B, because session A hadn't been committed, 'C' had been locked by session A. However, if execute a delete sql, session B will try to add lock in the following sequence:
gap lock before 'C': Success, because innodb could add multi gap lock in the same position.
record lock 'C': Blocked, because session A have holded that lock. session B have to wait it released by session A.
gap lock before 'D':
At last, session A send insert into t (name) values ('B');. For table t, there are 2 indexes, which are id and name. id is a auto increasement primary integer key, and for name, this sql will try to add a insert intention lock. However, there have been a gap lock which is holded by session B, therefor session A have to wait session B for releasing that gap lock. Now we could see how this dead lock occur. Innodb will choose a session to rollback base on cost. Here session B will be rolled back.
For Q1, the anwser is yes.
For Q2, actually, the deleted record wouldn't be purged from an index before its session commit.
For Q3, row lock number is equal to trx_rows_locked, and in mysql website, its:
TRX_ROWS_LOCKED
The approximate number or rows locked by this transaction. The value
might include delete-marked rows that are physically present but not
visible to the transaction.
From this article, we could know:
For non-clustered unique index filtering, due to the need to return tables, the number of filtered rows is locked as the unique index plus
the number of returned rows.
For non-clustered non-unique index filtering, the gap lock is involved, so more records are locked.
So, trx_rows_locked (gap lock + next-key lock + return table) is 3 after delete in session A. final trx_rows_locked value should be 3 + 1 (insert key lock) after trying to insert.
The following are for the new update questions:
I didn't notice delete primary key and unique secondary key before.
After some investigating, I found:
When deleting a primary key, which have been deleted and not commited yet, the new delete operation will only require record lock instead of next-key lock.
When deleting a secondary unique key, which have been deleted and not commited yet, the new delete operation will require next-key lock.
You could use set GLOBAL innodb_status_output_locks=ON; show engine innodb status to see the detail lock status for running trasactions.
For Q4, I finally found a comment in MySQL 5.7 source code that explain why using next-key locks, just for reference.
In a search where at most one record in the index may match, we
can use a LOCK_REC_NOT_GAP type record lock when locking a
non-delete-marked matching record.
Note that in a unique secondary index there may be different
delete-marked versions of a record where only the primary key
values differ: thus in a secondary index we must use next-key
locks when locking delete-marked records
Note above that a UNIQUE secondary index can contain many
rows with the same key value if one of the columns is the SQL
null. A clustered index under MySQL can never contain null
columns because we demand that all the columns in primary key
are non-null.

MySQL deadlock occurs in unique key when "replace into" statement is used

Summarize the problem
A deadlock problem occurs when the statement as "replace into model_test values(1, abc, 111)" and the statement as "replace into model_test values(2, abcd, 123)" execute at the same time in a multi-thread environment.
Show some codes
In the production environment, a table like this(simplification):
id name value
1 abc 111
2 abcd 123
create table statement as:
CREATE TABLE `db_research`.`model_test` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NULL,
`value` INT(11) NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `name_UNIQUE` (`name` ASC));
When I execute show engine innodb status,we can see some information about "LATEST DETECTED DEADLOCK"
Provide background including what you've alreadly tried
MySQL version : 8.0.11
I have tried to split replace into statement into delete statement and insert statement.
transaction2:
mysql>begin;
mysql>delete from model_test where id = 2;
Query OK,1 row affected(0.02 sec)
transaction1:
mysql>begin;
mysql>replace into model_test values(1,'abc',111);
(waiting...)
transaction2:
mysql>insert into model_test values(2,'abcd',123);
Query OK,1 row affected(0.08 sec)
transaction1:
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
show engine innodb status :
*** (1) TRANSACTION:
LOCK WAIT 4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 2
replace into model_test values(1,'abc','111')
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3565 page no 4 n bits 72 index name_UNIQUE of table `db_research`.`model_test` trx id 1238711 lock_mode X waiting
*** (2) TRANSACTION:
5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
insert into model_test values(2,'abcd','123')
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 3565 page no 4 n bits 72 index name_UNIQUE of table `db_research`.`model_test` trx id 1238710 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 3565 page no 4 n bits 72 index name_UNIQUE of table `db_research`.`model_test` trx id 1238710 lock mode S waiting
*** WE ROLL BACK TRANSACTION (1)
Is it due to MySQL's next-key lock on the unique key?

MySQL (InnoDB) deadlock

We are struggling with one deadlock which is occuring multiple times a day in our production environment.
------------------------
LATEST DETECTED DEADLOCK
------------------------
2018-12-27 19:07:34 7fcef1959700
*** (1) TRANSACTION:
TRANSACTION 2125001468, ACTIVE 2 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1184, 2 row lock(s), undo log entries 1
MySQL thread id 42190185, OS thread handle 0x7fcffc0b1700, query id 918842488 --- updating
UPDATE synchronization SET service_synchronized_at = NULL WHERE id = 116212
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 615 page no 288 n bits 528 index `PRIMARY` of table `app`.`synchronization` trx table locks 1 total table locks 2 trx id 2125001468 lock_mode X locks rec but not gap waiting lock hold time 2 wait time before grant 0
*** (2) TRANSACTION:
TRANSACTION 2125001355, ACTIVE 5 sec fetching rows
mysql tables in use 2, locked 2
25216 lock struct(s), heap size 3683880, 5297668 row lock(s), undo log entries 94
MySQL thread id 42189517, OS thread handle 0x7fcef1959700, query id 918842042 --- updating
UPDATE synchronization s SET s.service_synchronized_at = now() WHERE s.service_synchronized_at IS NULL AND s.user_id IN (* time consuming select to determine which users should be updated *)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 615 page no 288 n bits 528 index `PRIMARY` of table `app`.`synchronization` trx table locks 2 total table locks 2 trx id 2125001355 lock_mode X lock hold time 3 wait time before grant 0
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 615 page no 2313 n bits 472 index `PRIMARY` of table `app`.`synchronization` trx table locks 2 total table locks 2 trx id 2125001355 lock_mode X waiting lock hold time 0 wait time before grant 0
*** WE ROLL BACK TRANSACTION (1)
In one query I want to set service_synchronized_at = NULL. service_synchronized_at is always not null in first query before update.
In second query I add a where condition s.service_synchronized_at IS NULL thinking it would result in non-locking rows with not null values. Guess I was wrong.
The table has only primary index on id and unique constraint on user_id (and of course foreign key on user_id).
Any help is welcome.

Why is there a deadlock with these two queries?

Isolation level is READ COMMITTED
The one query is looking for records where service_id is 0 ... the other is looking where service_id is NOT IN (0, ... others ... );
I'd think they would be locking different rows?
------------------------
LATEST DETECTED DEADLOCK
------------------------
2017-08-18 09:01:24 7f2d05641700
*** (1) TRANSACTION:
TRANSACTION 201694975, ACTIVE 1 sec starting index read
mysql tables in use 2, locked 2
LOCK WAIT 46 lock struct(s), heap size 6544, 194 row lock(s)
MySQL thread id 33600289, OS thread handle 0x7f2d0812b700, query id 3703173090 inf-rtpctllb02-prd.rtp.netapp.com 10.60.56.150 ctl Copying to tmp table
SELECT
re.*,
r.config_id,
r.reserve_all_or_nothing,
r.owner,
r.charges
FROM
`job_charge` AS re,
`job` AS r WHERE
re.job_id = r.id AND ((re.status ='dispatched') or (re.status= 'running') or (re.status= 'held') or (re.status= 'reserved')) AND ((re.service_id ='0')) AND r.disable = 0 ORDER BY r.priority,r.id LIMIT 10000 FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1485 page no 987 n bits 104 index `PRIMARY` of table `ctl`.`job_charge` trx table locks 2 total table locks 2 trx id 201694975 lock_mode X locks rec but not gap waiting lock hold time 1 wait time before grant 0
*** (2) TRANSACTION:
TRANSACTION 201691925, ACTIVE 185 sec fetching rows
mysql tables in use 4, locked 2
1164 lock struct(s), heap size 128552, 2 row lock(s)
MySQL thread id 33599597, OS thread handle 0x7f2d05641700, query id 3703158120 inf-rtpctllb02-prd.rtp.netapp.com 10.60.56.150 ctl updating
UPDATE
`job_charge`
SET
service_id = '0'
WHERE
service_id NOT IN ('0','ctl5-staging_command-launcher.674d8c96-7c76-11e7-bc6c-ee0cf095fd00','inf-mesos-slave001.ctl.gdl.englab.netapp.com:mesos-6b256982-4ef1-4a84-ba60-58245ee7406d-S63.3987fd54-ee31-4c81-add4-4be53a6ed363:80','ctl5-staging_scheduler.912d008f-7c76-11e7-bc6c-ee0cf095fd00','ctl5-production_capacity-manager.6a869ee7-7919-11e7-bc6c-ee0cf095fd00','ctl5-production_scheduler.91de7d76-7919-11e7-bc6c-ee0cf095fd00','mysql','inf-mesos-slave001.ctl.gdl.englab.netapp.com:mesos-6b256982-4ef1-4a84-ba60-58245ee7406d-S63.48fe0555-83e9-4811-bcbc-f301da498fa6:80','ctl5-production_cleaner.6a86c5fa-7919-11e7-bc6c-ee0cf095fd00','ctl5-production_command-launcher.9f97a534-8413-11e7-bc6c-ee0cf095fd00','ctl5-production_reservation-manager.7ac1771d-7a9e-11e7-bc6c-ee0cf095fd00','ctl5-s
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1485 page no 987 n bits 104 index `PRIMARY` of table `ctl`.`job_charge` trx table locks 1 total table locks 2 trx id 201691925 lock_mode X locks rec but not gap lock hold time 13 wait time before grant 12
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1485 page no 1606 n bits 88 index `PRIMARY` of table `ctl`.`job_charge` trx table locks 1 total table locks 2 trx id 201691925 lock_mode X locks rec but not gap waiting lock hold time 0 wait time before grant 0
*** WE ROLL BACK TRANSACTION (1)
Yes. Both must be different rows. You can see the page no 987 and 1606 as indicated in the statement
Here Transaction 1 is
SELECT
re.*,
r.config_id,
r.reserve_all_or_nothing,
r.owner,
r.charges
FROM
`job_charge` AS re,
`job` AS r WHERE
re.job_id = r.id AND ((re.status ='dispatched') or (re.status= 'running') or (re.status= 'held') or (re.status= 'reserved')) AND ((re.service_id ='0')) AND r.disable = 0 ORDER BY r.priority,r.id LIMIT 10000 FOR UPDATE
Transaction 2 is
UPDATE
`job_charge`
SET
service_id = '0'
WHERE
service_id NOT IN ('0','ctl5-staging_command-launcher.674d8c96-7c76-11e7-bc6c-ee0cf095fd00','inf-mesos-slave001.ctl.gdl.englab.netapp.com:mesos-6b256982-4ef1-4a84-ba60-58245ee7406d-S63.3987fd54-ee31-4c81-add4-4be53a6ed363:80','ctl5-staging_scheduler.912d008f-7c76-11e7-bc6c-ee0cf095fd00','ctl5-production_capacity-manager.6a869ee7-7919-11e7-bc6c-ee0cf095fd00','ctl5-production_scheduler.91de7d76-7919-11e7-bc6c-ee0cf095fd00','mysql','inf-mesos-slave001.ctl.gdl.englab.netapp.com:mesos-6b256982-4ef1-4a84-ba60-58245ee7406d-S63.48fe0555-83e9-4811-bcbc-f301da498fa6:80','ctl5-production_cleaner.6a86c5fa-7919-11e7-bc6c-ee0cf095fd00','ctl5-production_command-launcher.9f97a534-8413-11e7-bc6c-ee0cf095fd00','ctl5-production_reservation-manager.7ac1771d-7a9e-11e7-bc6c-ee0cf095fd00','ctl5-s
From the given message, we can see that transaction 1 is waiting for an Exclusive Lock (Denoted by X lock, lock needed for WRITING some value into the table) on the table 'ctl' primary key.
But at the same time, transaction 2 came into the picture which is already holding an X lock on the 'ctl' table primary key (page no 987). So, as transaction 2 is already having an X lock on 'ctl', transaction 1 can't get X lock and hence it is waiting.
But transaction 2 itself is waiting for another X lock on 'ctl' (different row from above, page no 1606). I think this row is being held by transaction 1.
So,
transaction 1 is holding a lock on a row in page no 1606 for which transaction 2 is waiting
and
transaction 2 is holding a lock on row in page no 987 for which transaction 1 is waiting
So, both are waiting for each other and hence deadlock occurred.

Baffling InnoDB deadlock

This InnoDB deadlock is really making me pull my hair. As far as I can see:
the transaction (1) is waiting for the PRIMARY on "applications"
The latter has been acquired by (2) for some rather long running updates (SELECT * FROM applications WHERE ID = xxxx FOR UPDATE)
So far, so good - one would expect (1) to wait for the lock and then get on with its work.
However, once (2) gets ready to save it's work (and commit the transaction), it fails with a deadlock since for some reason (1) has managed to get a lock on some secondary index. How the hell did (1) manage to get any locks on the row if the PRIMARY is being held by (2).
One would expect that if (2) originally acquired the PRIMARY lock (SELECT * FROM applications WHERE ID = xxxx FOR UPDATE) it would also have set locks on all the secondary indexes. Is it possible that it will not lock the "tasked" index if tasked==NULL thus allowing (1) acquire a lock on "tasked" before even getting a lock on PRIMARY?
I have had no luck replication this scenario..
Thank you!
Lauri
------------------------
LATEST DETECTED DEADLOCK
------------------------
130428 17:04:06
*** (1) TRANSACTION:
TRANSACTION A369A8C, ACTIVE 1 sec fetching rows
mysql tables in use 3, locked 3
LOCK WAIT 217 lock struct(s), heap size 31160, 636 row lock(s)
MySQL thread id 13310554, OS thread handle 0x7f06cc2d7700, query id 177699568 217.146.78.151 shard67 Sending data
SELECT `applications`.* FROM `applications`
LEFT JOIN `applicants` ON applicants.ID = applications.applicant_ID
LEFT JOIN `regions` ON regions.ID = applicants.region_ID WHERE (status <> 'Blank') AND (status <> 'Closed') AND (revised < 1367154245) AND (tasked IS NULL OR tasked < 1367147045) AND (commence_year >= '2013') AND (regions.instance_ID = '1') ORDER BY `tasked` ASC, `ID` ASC LIMIT 20 FOR UPDATE
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 20021 page no 1192 n bits 80 index `PRIMARY` of table `dream-shard67`.`applications` trx id A369A8C lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION A369A87, ACTIVE 1 sec updating or deleting
mysql tables in use 1, locked 1
16 lock struct(s), heap size 3112, 22 row lock(s), undo log entries 5
MySQL thread id 13310563, OS thread handle 0x7f06cc151700, query id 177699599 217.146.76.127 shard67
UPDATE `applications` SET `revised` = '1367157846', `tasked` = '1367157846', `revision_ID` = '140649', `xml` = 'Zms6\noMmI$%[v....snipped binary data
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 20021 page no 1192 n bits 72 index `PRIMARY` of table `dream-shard67`.`applications` trx id A369A87 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 20021 page no 292 n bits 1280 index `tasked` of table `dream-shard67`.`applications` trx id A369A87 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (2)
Make sure your doing most of these:
http://dev.mysql.com/doc/refman/5.0/en/innodb-deadlocks.html