2017-05-15 5 views
0

Ich habe die folgende Abfrage:MySQL selbst beitreten Deadlock

UPDATE messages QM JOIN (SELECT id FROM messages WHERE name = 'name' 
AND state = 0 ORDER BY priority DESC, timestamp DESC LIMIT 1) AS QM2 
ON QM.name ='name' AND QM.id = QM2.id SET QM.weight = QM.weight + 1; 

(Ich brauche hier selbst beitreten, weil MySQL nicht in der Lage Indizes zu verwenden, um BY mit einfachen Update)

Dort wird der Composite-Index ist auf (name, state, priority, timestamp) Spalten. Es stimmt perfekt mit der obigen Abfrage überein.

Mein Problem ist, eine riesige Menge von Deadlocks, wenn die Abfragerate> 80 rps:

------------------------ 
LATEST DETECTED DEADLOCK 
------------------------ 
2017-05-15 12:04:49 7f7992119b00 
*** (1) TRANSACTION: 
TRANSACTION 3923289, ACTIVE 0 sec starting index read 
mysql tables in use 2, locked 2 
LOCK WAIT 4 lock struct(s), heap size 1184, 4 row lock(s) 
MySQL thread id 992, OS thread handle 0x7f7958b5eb00, query id 1325283 172.17.0.1 facade Sending data 
UPDATE queue_messages m1 JOIN 
     (SELECT id FROM queue_messages WHERE queue_name = ? AND state = 0 ORDER BY priority DESC, message_timestamp DESC LIMIT ?) 
      AS m2 ON m1.queue_name = ? AND m1.id = m2.id SET m1.state = 1, m1.transient_token = ?, m1.transient_token_expiration_timestamp = ?, m1.retry_count = retry_count + 1 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 1772 page no 2464 n bits 304 index `QUEUE_NAME_STATE_PRIORITY_MESSAGE_TIMESTAMP_INDEX` of table `actionmq_data`.`queue_messages` trx table locks 1 total table locks 4 trx id 3923289 lock mode S waiting lock hold time 0 wait time before grant 0 

*** (2) TRANSACTION: 
TRANSACTION 3923243, ACTIVE 0 sec updating or deleting 
mysql tables in use 2, locked 2 
9 lock struct(s), heap size 2936, 9 row lock(s), undo log entries 1 
MySQL thread id 975, OS thread handle 0x7f7992119b00, query id 1325044 172.17.0.1 facade updating reference tables 
UPDATE queue_messages m1 JOIN 
     (SELECT id FROM queue_messages WHERE queue_name = ? AND state = 0 ORDER BY priority DESC, message_timestamp DESC LIMIT ?) 
      AS m2 ON m1.queue_name = ? AND m1.id = m2.id SET m1.state = 1, m1.transient_token = ?, m1.transient_token_expiration_timestamp = ?, m1.retry_count = retry_count + 1 
*** (2) HOLDS THE LOCK(S): 
RECORD LOCKS space id 1772 page no 2464 n bits 304 index `QUEUE_NAME_STATE_PRIORITY_MESSAGE_TIMESTAMP_INDEX` of table `actionmq_data`.`queue_messages` trx table locks 2 total table locks 4 trx id 3923243 lock_mode X locks rec but not gap lock hold time 0 wait time before grant 0 
*** (2) WAITING FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 1772 page no 2469 n bits 168 index `QUEUE_NAME_STATE_PRIORITY_MESSAGE_TIMESTAMP_INDEX` of table `actionmq_data`.`queue_messages` trx table locks 2 total table locks 4 trx id 3923243 lock_mode X locks gap before rec insert intention waiting lock hold time 0 wait time before grant 0 
*** WE ROLL BACK TRANSACTION (1) 

, wie ich das beheben kann?

Antwort

0

Können Sie dies versuchen:

UPDATE messages QM SET QM.weight = (QM.weight + 1) WHERE QM.id = (SELECT id FROM messages WHERE name = 'name' AND state = 0 ORDER BY priority DESC, timestamp DESC LIMIT 1) 
+0

Hallo. Leider habe ich folgenden Fehler mit diesem Ansatz: 'Tabelle 'QM' ist zweimal angegeben, sowohl als Ziel für 'UPDATE' und als separate Quelle für Daten ' –

+0

Versuchen Sie dies: ' UPDATE Nachrichten QM SET QM.weight = (QM .weight + 1) WHERE QM.id = (Wählen Sie * aus (SELECT ID FROM Nachrichten WHERE Name = 'Name' AND Status = 0 ORDER BY Priorität DESC, Zeitstempel DESC LIMIT 1) m) ' –

0

Wenn id die PRIMARY KEY, dann auf name Beitritt ist redundant:

ON QM.name ='name' AND QM.id = QM2.id 

sehen, ob dies besser funktioniert:

BEGIN; 
SELECT @id := id 
    FROM messages 
    WHERE name = 'name' 
     AND state = 0 
    ORDER BY priority DESC, timestamp DESC 
    LIMIT 1 
    FOR UPDATE; 
UPDATE messages 
    SET weight = weight + 1 
    WHERE id = @id; 
COMMIT; 

Oder

UPDATE messages 
    SET weight = weight + 1 
    WHERE id = (SELECT id 
        FROM messages 
        WHERE name = 'name' 
        AND state = 0 
        ORDER BY priority DESC, timestamp DESC 
        LIMIT 1 
       ); 

Oder einfach

UPDATE messages 
    SET weight = weight + 1 
    WHERE name = 'name' 
     AND state = 0 
    ORDER BY priority DESC, timestamp DESC 
    LIMIT 1;