为什么InnoDB CREATE ... SELECT使用独占锁?

时间:2011-05-11 22:56:12

标签: mysql innodb deadlock database-deadlocks

我正试图围绕偶尔出现的InnoDB僵局:

------------------------
LATEST DETECTED DEADLOCK
------------------------
110511 10:45:59
*** (1) TRANSACTION:
TRANSACTION 0 959459752, ACTIVE 0 sec, process no 24148, OS thread id 2958613424 starting index read
mysql tables in use 16, locked 16
LOCK WAIT 2 lock struct(s), heap size 320
MySQL thread id 13029007, query id 85826239 localhost andrew updating
DELETE FROM `clients_permission_assignments` WHERE permission_assignment_id = 3761 AND client_id IN (52621)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 1490959 n bits 864 index `unique_index` of table `test/clients_permission_assignments` trx id 0 959459752 lock_mode X waiting
Record lock, heap no 202 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
 0: len 4; hex 8000cd8d; asc     ;; 1: len 4; hex 80000eb1; asc     ;; 2: len 6; hex 0000006b7d5c; asc    k}\;;

*** (2) TRANSACTION:
TRANSACTION 0 959459751, ACTIVE 0 sec, process no 24148, OS thread id 1996331952 fetching rows, thread declared inside InnoDB 354
mysql tables in use 16, locked 16
20 lock struct(s), heap size 2496, undo log entries 1
MySQL thread id 13019094, query id 85826237 localhost andrew Copying to tmp table
CREATE TEMPORARY TABLE tmp_tests_people_cleanup_table (SELECT unit_code FROM (
              SELECT u.unit_code, COUNT(u.unit_code) AS cnt FROM staging.client_test_utilization u
              LEFT JOIN permission_assignments pa ON pa.person_id =
                  (SELECT person_id FROM permission_assignments pa WHERE pa.id = OLD.permission_assignment_id)
              LEFT JOIN permissions p ON pa.permission_id = p.id
              LEFT JOIN clients_permission_assignments cpa ON cpa.permission_assignment_id = pa.id
              LEFT JOIN clients c ON c.id = cpa.client_id
              LEFT JOIN staging.client_test_utilization u2 ON CONCAT('C',u2.client_number) = c.number
                  AND u2.unit_code = u.unit_code
              WHERE p.label = 'Receive Test Updates'
                  AND CONCAT('C',u.client_number) = (SELECT number from clients WHERE id = OLD.client_id)
                  AND u2.id IS NULL GROUP BY u.unit_code
          ) tbl
          WHERE cnt = (SELECT COUNT(*) FROM permission_assignments pa
                      LEFT JOIN permissions p ON pa.permission_id = p.id
                      LEFT JOIN clients_permission_assignments cpa ON cpa.permission_assignment_id = pa.id
                      WHERE p.label = 'Receive Test Updates' AND pa.person_id =
                          (SELECT person_id FROM permission_assignments pa WHERE pa.id = OLD.permission_assignment_id))
              OR (SELECT COUNT(*) FROM permission_assignments pa
                      LEFT JOIN permissions p ON pa.permission_id = p.id
                      LEFT JOIN clients_permission_assignments cpa ON cpa.permission_assignment_id = pa.id
                      WHERE p.label = 'Receive Test Updates' AND pa.person_id =
                          (SELECT person_id FROM permission_assignments pa WHERE pa.id = OLD.permission_assignment_id)) = 0)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 1490959 n bits 864 index `unique_index` of table `test/clients_permission_assignments` trx id 0 959459751 lock_mode X locks rec but not gap
Record lock, heap no 202 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
 0: len 4; hex 8000cd8d; asc     ;; 1: len 4; hex 80000eb1; asc     ;; 2: len 6; hex 0000006b7d5c; asc    k}\;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 1490959 n bits 864 index `unique_index` of table `test/clients_permission_assignments` trx id 0 959459751 lock mode S waiting
Record lock, heap no 202 PHYSICAL RECORD: n_fields 3; compact format; info bits 32
 0: len 4; hex 8000cd8d; asc     ;; 1: len 4; hex 80000eb1; asc     ;; 2: len 6; hex 0000006b7d5c; asc    k}\;;

*** WE ROLL BACK TRANSACTION (1)

我当时不知道,但似乎INSERT ... SELECT,CREATE ... SELECT锁定SELECT查询中的所有表。如您所见,有很多表包含连接和子查询。我认为锁将是一个共享(S)锁,但从上面的数据来看,它似乎拥有一个独占(X)锁;我不明白为什么。

也许如果有人可以帮我解释为什么在CREATE上有一个独占(X)锁定... SELECT查询我可以尝试解决这个死锁问题。或许我可以从僵局中获得进一步的帮助。

谢谢。

1 个答案:

答案 0 :(得分:0)

我发现独占锁不是来自CREATE ... SELECT查询,而是它之前的查询,它必须在同一个事务中。

我遗漏了一个重要的细节:CREATE ... SELECT查询是clients_permission_assignments上的AFTER DELETE触发器。我发现问题是DELETE查询在某些clients_permission_assignments记录上持有独占锁,并且在每次删除之后,CREATE ... SELECT查询尝试在已经具有独占锁的记录上获取共享锁DELETE查询。 CREATE ... SELECT查询必须等待删除所有行并释放独占锁。但是,当这个过程发生时,用户没有享受等待,所以他们再次启动了DELETE查询,这导致了死锁。

谢谢。