何时以及为什么会发生这种死锁?

Sau*_*abh 3 mysql innodb deadlock

------------------------
LATEST DETECTED DEADLOCK
------------------------
130409  0:40:58
*** (1) TRANSACTION:
TRANSACTION 3D61D41F, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 43 lock struct(s), heap size 6960, 358 row lock(s), undo log entries 43
MySQL thread id 17241690, OS thread handle 0x7ffd3469a700, query id 860259163 localhost root update
INSERT INTO `notification` (`other_grouped_notifications_count`, `user_id`, `notifiable_type`, `action_item`, `action_id`, `created_at`, `status`, `updated_at`) VALUES (0, 4442, 'MATCH', 'MATCH', 224716, 1365448255, 1, 1365448255)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 272207 n bits 1272 index `user_id` of table `notification` trx id 3D61D41F lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 69 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 8000115b; asc    [;;
 1: len 4; hex 0005e0bb; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 3D61C472, ACTIVE 15 sec starting index read
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1248, 2 row lock(s)
MySQL thread id 17266704, OS thread handle 0x7ffd34b01700, query id 860250374 localhost root Updating
UPDATE `notification` SET `status`=0 WHERE user_id = 4443 and status=1
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 272207 n bits 1272 index `user_id` of table `notification` trx id 3D61C472 lock_mode X
Record lock, heap no 69 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 8000115b; asc    [;;
 1: len 4; hex 0005e0bb; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 261029 n bits 248 index `PRIMARY` of table `notification` trx id 3D61C472 lock_mode X locks rec but not gap waiting
Record lock, heap no 161 PHYSICAL RECORD: n_fields 16; compact format; info bits 0
 0: len 4; hex 0005e0bb; asc     ;;
 1: len 6; hex 00000c75178f; asc    u  ;;
 2: len 7; hex 480007c00c1d10; asc H      ;;
 3: len 4; hex 8000115b; asc    [;;
 4: len 8; hex 5245474953544552; asc REGISTER;;
 5: SQL NULL;
 6: SQL NULL;
 7: SQL NULL;
 8: len 4; hex d117dd91; asc     ;;
 9: len 4; hex d117dd91; asc     ;;
 10: len 1; hex 80; asc  ;;
 11: SQL NULL;
 12: SQL NULL;
 13: SQL NULL;
 14: SQL NULL;
 15: len 4; hex 80000000; asc     ;;

*** WE ROLL BACK TRANSACTION (2)
------------
TRANSACTIONS
------------
Trx id counter 3DBAB14A
Purge done for trx's n:o < 3DBAAF69 undo n:o < 0
History list length 1911
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 17555159, OS thread handle 0x7ffd342f7700, query id 874625123 localhost root
show engine innodb status
---TRANSACTION 3DBAB148, not started
MySQL thread id 17557253, OS thread handle 0x7ffd34a9f700, query id 874625122 localhost root
---TRANSACTION 3DBAB0F0, not started
MySQL thread id 17557249, OS thread handle 0x7ffd34948700, query id 874624797 localhost root
---TRANSACTION 3DBAB0FF, not started
MySQL thread id 17546322, OS thread handle 0x7ffd343bb700, query id 874624821 localhost root
---TRANSACTION 3DBAB0FE, not started
MySQL thread id 17546288, OS thread handle 0x7ffd3441d700, query id 874624819 localhost root
---TRANSACTION 3DBAB0FB, not started
MySQL thread id 17546267, OS thread handle 0x7ffd34543700, query id 874624818 localhost root
---TRANSACTION 3DBAB0FA, not started
MySQL thread id 17546259, OS thread handle 0x7ffd34638700, query id 874624817 localhost root
---TRANSACTION 3DBAB01D, not started
MySQL thread id 17546253, OS thread handle 0x7ffbfce8f700, query id 874624182 localhost root
---TRANSACTION 3DBAB00A, not started
MySQL thread id 17546252, OS thread handle 0x7ffd34d4d700, query id 874624151 localhost root
---TRANSACTION 3DBAB101, not started
MySQL thread id 17546251, OS thread handle 0x7ffd34359700, query id 874624824 localhost root
---TRANSACTION 3DBAB100, not started
MySQL thread id 17546249, OS thread handle 0x7ffd34853700, query id 874624823 localhost root
---TRANSACTION 3DBAB102, not started
MySQL thread id 17546245, OS thread handle 0x7ffbfd079700, query id 874624825 localhost root
---TRANSACTION 0, not started
MySQL thread id 17509427, OS thread handle 0x7ffbfc0a8700, query id 872618032 localhost root
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
1251611 OS file reads, 59363166 OS file writes, 43388223 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 37.85 writes/s, 35.43 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 6378, seg size 6380, 45209 merges
merged operations:
 insert 467359, delete mark 13737931, delete 888610
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 8850487, node heap has 15036 buffer(s)
296481.25 hash searches/s, 4879.87 non-hash searches/s
---
LOG
---
Log sequence number 174590808256
Log flushed up to   174590808256
Last checkpoint at  174589633376
0 pending log writes, 0 pending chkp writes
42519161 log i/o's done, 35.28 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 4395630592; in additional pool allocated 0
Dictionary memory allocated 829252
Buffer pool size   262144
Free buffers       16
Database pages     247092
Old database pages 91191
Modified db pages  755
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 4120399, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 2422849, created 679606, written 29056740
0.00 reads/s, 0.00 creates/s, 2.86 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 247092, unzip_LRU len: 0
I/O sum[705]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 30911, id 140720292824832, state: sleeping
Number of rows inserted 30042313, updated 60944284, deleted 28858062, read 2514515901102
11.36 inserts/s, 28.57 updates/s, 4.00 deletes/s, 436602.24 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================  
Run Code Online (Sandbox Code Playgroud)

通知表中的索引是 -

id - Primary key  
user_id - non-unique index  
Run Code Online (Sandbox Code Playgroud)

Rol*_*DBA 5

让我们看看死锁的查询:

在 下TRANSACTION 3D61D41F,您有以下查询:

INSERT INTO `notification` (`other_grouped_notifications_count`, `user_id`,
`notifiable_type`, `action_item`, `action_id`, `created_at`, `status`, `updated_at`)
VALUES (0, 4442, 'MATCH', 'MATCH', 224716, 1365448255, 1, 1365448255)
Run Code Online (Sandbox Code Playgroud)

在 下TRANSACTION 3D61C472,您有以下查询:

UPDATE `notification` SET `status`=0 WHERE user_id = 4443 and status=1
Run Code Online (Sandbox Code Playgroud)

这些查询怎么会陷入僵局?

要回答这个问题,您必须了解 InnoDB 存储引擎如何处理索引。首先,单击此处查看 InnoDB 基础设施的图示

这里还有一些开始:gen_clust_index,更好地称为聚集索引。它是PRIMARY KEY. 正如MySQL 文档所说:

除聚集索引外的所有索引都称为二级索引。在 InnoDB 中,二级索引中的每条记录都包含该行的主键列,以及为二级索引指定的列。InnoDB 使用这个主键值来搜索聚集索引中的行。

如果主键很长,二级索引会占用更多的空间,所以主键短是有利的。

由于二级索引中的条目包含返回聚集索引的键,因此需要进行一些处理以将二级键与相应的 PRIMARY KEY 条目对齐。这是在 ibdata1(系统表空间)中包含的插入缓冲区中执行的。

现在,回顾一下查询。

第一个查询INSERT来自的查询TRANSACTION 3D61D41F必须锁定 gen_clust_index 中新生成的条目。它还必须在二级索引中为 user_id 4442 创建一个条目,并且必须携带新创建的 gen_clust_index 键并在插入缓冲区中一起处理它们。

SECOND QUERYUPDATE查询中的查询TRANSACTION 3D61C472必须锁定 user_id 为 4443 的现有行。因此,需要锁定相应的 gen_clust_index 条目。

共同锁定

TRANSACTION 3D61D41F

RECORD LOCKS space id 0 page no 272207 n bits 1272 index `user_id`
0: len 4; hex 8000115b; asc    [;;
1: len 4; hex 0005e0bb; asc     ;;
Record lock, heap no 69 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
Run Code Online (Sandbox Code Playgroud)

TRANSACTION 3D61C472

RECORD LOCKS space id 0 page no 272207 n bits 1272 index `user_id`
0: len 4; hex 8000115b; asc    [;;
1: len 4; hex 0005e0bb; asc     ;;
Record lock, heap no 69 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
Run Code Online (Sandbox Code Playgroud)

两个事务都需要 gen_clust_index 的相同部分

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 261029 n bits 248 index `PRIMARY` of table `notification` trx id 3D61C472 lock_mode X locks rec but not gap waiting
Record lock, heap no 161 PHYSICAL RECORD: n_fields 16; compact format; info bits 0
Run Code Online (Sandbox Code Playgroud)

据此,UPDATE查询已尝试先锁定。不幸的是,这很公平,因为它UPDATE适用于已经存在的行。在INSERT试图创建一个新的行。它必须在UPDATE.

这解决了为什么会在这个特定实例中发生死锁的谜团。