2011-05-11 53 views
0

我試圖環繞的InnoDB的僵局,偶爾表現出來了我的頭:爲什麼InnoDB CREATE ... SELECT使用獨佔鎖?

------------------------ 
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 ... SELECT查詢上有一個獨佔(X)鎖定,我可以試圖解決這個死鎖問題。或者,也許我可以在僵局中獲得進一步的幫助。

謝謝。

+0

你正在使用什麼隔離級別? – 2011-05-11 23:05:00

+0

它似乎是MySQL的默認設置(REPEATABLE READ)。我在過去使用了'SET TRANSACTION ISOLATION LEVEL READ COMMITTED;'來解決INSERT ... SELECT問題;你認爲這也會有用嗎? – 2011-05-11 23:09:21

回答

0

我發現獨佔鎖不是來自CREATE ... SELECT查詢,而是它之前的查詢,它必須在同一個事務中。

我遺漏了一個重要的細節:CREATE ... SELECT查詢是clients_permission_assignments上的AFTER DELETE觸發器。我發現問題是DELETE查詢在某些clients_permission_assignments記錄上持有排他鎖,並且在每次刪除之後,CREATE ... SELECT查詢嘗試從已經具有DELETE查詢獨佔鎖的記錄上獲取共享鎖。 CREATE ... SELECT查詢必須等待刪除所有行並釋放排它鎖。然而,在這個過程發生的時候,用戶並沒有在等待,所以他們再次啓動了DELETE查詢,這導致了死鎖。

謝謝。