Mysql
 sql >> Database >  >> RDS >> Mysql

Errore di deadlock MySQL

Dopo aver letto un po' di più, ho scoperto che, poiché InnoDB utilizza il blocco a livello di riga, possono verificarsi deadlock durante l'inserimento o l'aggiornamento di una singola riga poiché le azioni non sono atomiche. Ho corso:

SHOW ENGINE INNODB STATUS

per trovare informazioni sull'ultimo deadlock. Ho trovato:

------------------------
LATEST DETECTED DEADLOCK
------------------------
140106 17:22:41
*** (1) TRANSACTION:
TRANSACTION 63EB5222A, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 9 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 2
MySQL thread id 4304350, OS thread handle 0x7fd3b74d3700, query id 173460207 192.168.0.2 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '27739' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1389046866'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB5222A lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 63EB52225, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
177 lock struct(s), heap size 31160, 17786 row lock(s), undo log entries 2
MySQL thread id 4304349, OS thread handle 0x7fd6961c8700, query id 173460194 192.168.0.1 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '30949' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1388964767'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 512 n bits 384 index `PRIMARY` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)

Puoi vedere che le due query che causano i deadlock sono in realtà le stesse esatte. Mostra che ci sono anche parametri diversi per le colonne nella clausola WHERE, quindi le righe effettive che vengono bloccate sono diverse, il che mi è sembrato un po' controintuitivo:in che modo le operazioni su diversi insiemi di righe possono causare un deadlock?

La risposta sembra essere che il deadlock deriva dalle voci di blocco del motore di query nelle strutture di indicizzazione. Se guardi l'output sopra, puoi vedere che una transazione ha un blocco su una determinata parte di una determinata pagina nel country index e necessita di un lock su parte dell'indice della chiave primaria, mentre l'altra transazione è essenzialmente il caso opposto.

Un'invariante in questa parte della nostra app è che solo una riga avrebbe mai meno di 1000 clic, quindi credo che risolvendo il problema il problema del deadlock sarà ridotto al minimo, poiché nel complesso ci sarebbero meno blocchi. La documentazione di MySQL suggerisce di codificare le tue applicazioni in modo che riemettano sempre le transazioni in caso di rollback a causa di un deadlock, il che eviterebbe che questo problema causi errori nelle pagine. Tuttavia, se qualcuno ha altre idee su come evitare effettivamente questi deadlock, di nuovo, per favore pubblicale nei commenti!

MODIFICA -

Il country index non doveva essere utilizzato dalla transazione, come per ogni camp_id valore c'erano solo una manciata (di solito solo 1) valori diversi di country , ognuno dei quali corrispondeva a una sola riga. Ho aggiunto un suggerimento per l'indice alla query per impedirne l'utilizzo e ora il problema è stato risolto senza alcun calo delle prestazioni (probabilmente un piccolo guadagno).