Ottenere "Timeout attesa di blocco superato; prova a riavviare la transazione "anche se non sto utilizzando una transazione


267

Sto eseguendo la seguente UPDATEdichiarazione MySQL :

mysql> update customer set account_import_id = 1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Non sto usando una transazione, quindi perché dovrei ricevere questo errore? Ho anche provato a riavviare il mio server MySQL e non ha aiutato.

La tabella ha 406.733 righe.

Risposte:


211

Stai utilizzando una transazione; autocommit non disabilita le transazioni, le fa semplicemente impegnare automaticamente alla fine dell'istruzione.

Quello che sta succedendo è che qualche altro thread ha un blocco dei record su un record (stai aggiornando tutti i record nella tabella!) Per troppo tempo e il tuo thread è scaduto.

Puoi vedere maggiori dettagli sull'evento emettendo un

SHOW ENGINE INNODB STATUS

dopo l'evento (in sqleditor). Idealmente, fallo su una macchina di prova silenziosa.


1
C'è un modo per salvare l'output in un file? Ho provato SHOW ENGINE INNODB STATUS \ G> innodb_stat.txt ma non funziona.
yantaq,

14
Dalla riga di comando: mysql [inserisci credenziali] -e "MOSTRA STATO INNODB MOTORE \ G"> innodb_stat.txt
VenerableAgents

se molti thread (o processi) mysql sono occupati, ad esempio alcune query richiedono molto tempo, quindi devi aspettare che alcune processsiano inattive. In tal caso potresti ottenere questo errore. Ho ragione?
zhuguowei,

6
Anche l'esecuzione di più (2+) query UPDATE sulla stessa riga durante una singola transazione provocherà questo errore.
Okneloper,

Per coloro che utilizzano Python MySQL Connector utilizzare connection.commit()per eseguire il commit INSERTo UPDATEhai appena girato.
AER,

334

COME FORZARE IL SBLOCCO per le tabelle bloccate in MySQL:

La rottura di blocchi come questo può impedire l' atomicità nel database sulle istruzioni sql che hanno causato il blocco.

Questo è un trucco, e la soluzione corretta è quella di riparare la tua applicazione che ha causato i blocchi. Tuttavia, quando i dollari sono in linea, un calcio rapido farà muovere di nuovo le cose.

1) Inserisci MySQL

mysql -u your_user -p

2) Vediamo l'elenco delle tabelle bloccate

mysql> show open tables where in_use>0;

3) Vediamo la lista dei processi correnti, uno di questi sta bloccando le tue tabelle

mysql> show processlist;

4) Uccidi uno di questi processi

mysql> kill <put_process_id_here>;

14
Questo è pericoloso e hacker. Una soluzione adeguata è quella di riparare la tua applicazione.
Zenexer,

71
Sciocchezze, questo ti consente di annullare un messaggio e quindi correggere l'applicazione. Se potessi dare a questo ragazzo 100 voti in più per questo problema che dovrei risolvere ORA lo farei.
Lizardx,

7
Sono d'accordo con Lizardx. Questa è stata una soluzione molto utile nella situazione che non avevo il privilegio di chiamare SHOW ENGINE INNODB STATUS
Travis Schneeberger

8
In che modo è pericoloso uccidere una query di lunga durata in questo modo ? La chiamata del client riceverà solo un errore.
Xeoncross,

7
@EricLeschinski Ho capito bene, ma devo chiederti perché mai dovresti usare un database sciatto come MySQL su un sistema Life-Critical ?
Xeoncross,

96
mysql> set innodb_lock_wait_timeout=100

Query OK, 0 rows affected (0.02 sec)

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 100   |
+--------------------------+-------+

Ora attiva nuovamente il blocco. Hai 100 secondi di tempo per inviare un SHOW ENGINE INNODB STATUS\Gal database e vedere quale altra transazione sta bloccando la tua.


8
Questa risposta non spiega perché il richiedente sta ottenendo il proprio errore. Potresti approfondire il motivo per cui oltre a dare la risposta?
Slitta

5
+1 anche se questo non risponde direttamente alla domanda, per me è un buon riferimento per risolvere il problema.
Jossef Harush,

1
@ArtB dev.mysql.com/doc/innodb/1.1/it/… In sostanza, l'OP sta ricevendo l'errore perché è stato chiamato un lock sul tavolo e il tempo trascorso prima di terminare la transazione ha superato il lock_wait_timeoutvalore
fyrye

70

Dai un'occhiata se il tuo database è ottimizzato. Soprattutto l'isolamento delle transazioni. Non è una buona idea aumentare la variabile innodb_lock_wait_timeout.

Controlla il livello di isolamento delle transazioni del database nel mysql cli:

mysql> SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation, @@session.transaction_isolation;
+-----------------------+-----------------+------------------------+
| @@GLOBAL.tx_isolation | @@tx_isolation  | @@session.tx_isolation |
+-----------------------+-----------------+------------------------+
| REPEATABLE-READ       | REPEATABLE-READ | REPEATABLE-READ        |
+-----------------------+-----------------+------------------------+
1 row in set (0.00 sec)

Potresti ottenere miglioramenti cambiando il livello di isolamento, usare l'oracolo come LEGGI IMPEGNATO invece RIPETIBILE LEGGI (Predefiniti InnoDB)

mysql> SET tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> SET GLOBAL tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)

mysql> 

Prova anche a utilizzare SELEZIONA PER AGGIORNAMENTO solo se necessario.


1
Questa è un'ottima soluzione per i problemi di blocco.
redolent

3
Funziona benissimo per me, la versione my.cnf è [mysqld] transazione-isolamento = LEGGI-IMPEGNATO
Benoit Gauthier,

Solo una nota: MySQL 8 ha rinominato la tx_isolationvariabile in transaction_isolation.
Xonya,

Bisogna però preoccuparsi di sapere in cosa ti stai cacciando quando passi dall'isolamento in lettura al READ COMMITTED. Potresti finire con dati sporchi che potresti voler evitare. Wikipedia Isoloation
huggie

27

Nessuna delle soluzioni suggerite ha funzionato per me ma questo ha funzionato.

Qualcosa sta bloccando l'esecuzione della query. Molto probabilmente un'altra query che aggiorna, inserisce o elimina da una delle tabelle nella query. Devi scoprire di cosa si tratta:

SHOW PROCESSLIST;

Una volta individuato il processo di blocco, trovalo ided esegui:

KILL {id};

Rieseguire la query iniziale.


Ho accidentalmente ucciso tutti i processi elencati con SHOW PROCESSLIST; Ora sto ricevendo un errore 500 in phpmyadmin. Quel 500 errore è legato all'uccisione di questi processi? Se sì, come posso riavviarlo.
Dashrath,

Posso vedere quello che descrivi, tuttavia uccidere il processo non funziona. Il comando process 'viene "ucciso", ma rimane nella lista dei processi.
Torsten,

12

100% con quanto affermato da MarkR. autocommit rende ogni istruzione una transazione con una sola istruzione.

SHOW ENGINE INNODB STATUSdovrebbe darti alcuni indizi sulla ragione del deadlock. Dai un'occhiata anche al log delle query lente per vedere cos'altro sta eseguendo una query sulla tabella e prova a rimuovere tutto ciò che sta eseguendo una scansione completa delle tabelle. Il blocco a livello di riga funziona bene ma non quando si tenta di bloccare tutte le righe!


5

È possibile aggiornare qualsiasi altro record all'interno di questa tabella o questa tabella è ampiamente utilizzata? Quello che sto pensando è che mentre sta tentando di acquisire un blocco, è necessario aggiornare questo record. Il timeout impostato è scaduto. Potresti essere in grado di aumentare il tempo utile.


3
forse innodb_lock_wait_timeoutinmy.cnf
obbligo

1
Ho impostato in my.cnf: <br/> innodb_lock_wait_timeout = 120 <br/> L'impostazione predefinita è 50 per mysql 5.5. Dopo questa modifica non sono riuscito a vedere questo problema nei test delle mie unità! Ciò è accaduto dopo il passaggio dal pool jdbc di proxool a tomcat. Probabilmente a causa di più tempo di transazione con il pool Tomcat ?!
Champ

3

Il numero di righe non è enorme ... Crea un indice su account_import_id se non è la chiave primaria.

CREATE INDEX idx_customer_account_import_id ON customer (account_import_id);

OMG ... questo mi ha appena salvato. Ho rovinato regalmente un DB di produzione rilasciando un indice e questo l'ha risolto. Grazie.
Nick Gotch,

2

Se hai appena ucciso una query di grandi dimensioni, ci vorrà del tempo per rollback. Se si emette un'altra query prima del rollback della query interrotta, è possibile che si verifichi un errore di timeout del blocco. Questo è quello che mi è successo. La soluzione era solo aspettare un po '.

Dettagli:

Avevo inviato una query DELETE per rimuovere circa 900.000 su circa 1 milione di righe.

L'ho eseguito per errore (rimuove solo il 10% delle righe): DELETE FROM table WHERE MOD(id,10) = 0

Invece di questo (rimuove il 90% delle righe): DELETE FROM table WHERE MOD(id,10) != 0

Volevo rimuovere il 90% delle righe, non il 10%. Quindi ho interrotto il processo nella riga di comando di MySQL, sapendo che avrebbe eseguito il rollback di tutte le righe che aveva eliminato finora.

Quindi ho eseguito immediatamente il comando corretto e lock timeout exceededsubito dopo ho ricevuto un errore. Mi sono reso conto che il blocco potrebbe effettivamente essere la rollbackquery uccisa che sta ancora accadendo in background. Quindi ho atteso qualche secondo e ho eseguito nuovamente la query.


1

Accertarsi che le tabelle del database stiano utilizzando il motore di archiviazione InnoDB e il livello di isolamento della transazione LEGGI-COMMITTATO.

Puoi verificarlo selezionando SELECT @@ GLOBAL.tx_isolation, @@ tx_isolation; sulla console mysql.

Se non è impostato su READ-COMMITTED, è necessario impostarlo. Assicurati prima di impostare che hai i privilegi SUPER in mysql.

Puoi chiedere aiuto su http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html .

Impostando questo penso che il tuo problema verrà risolto.


Potresti anche voler verificare che non stai tentando di aggiornare questo in due processi contemporaneamente. Gli utenti (@tala) hanno riscontrato messaggi di errore simili in questo contesto, forse ricontrollare che ...


1

Sono venuto da Google e volevo solo aggiungere la soluzione che funzionava per me. Il mio problema era che stavo cercando di eliminare i record di una tabella enorme che aveva un sacco di FK in cascata, quindi ho avuto lo stesso errore dell'OP.

Ho disabilitato autocommite poi ha funzionato solo aggiungendo COMMITalla fine della frase SQL. Per quanto ho capito, questo rilascia il buffer bit per bit invece di attendere alla fine del comando.

Per mantenere l'esempio del PO, questo avrebbe dovuto funzionare:

mysql> set autocommit=0;

mysql> update customer set account_import_id = 1; commit;

Non dimenticare di riattivare autocommitnuovamente se vuoi lasciare la configurazione di MySQL come prima.

mysql> set autocommit=1;


0

In ritardo alla festa (come al solito), tuttavia, il mio problema era il fatto che ho scritto un po 'di SQL errato (essendo un novizio) e diversi processi avevano un blocco sui record <- non sono sicuro della verbosità appropriata. Ho finito per dover solo: SHOW PROCESSLISTe poi uccidere gli ID usandoKILL <id>


0

Questo genere di cose mi è successo quando stavo usando exit di costruzione del linguaggio php; nel mezzo della transazione. Quindi questa transazione "si blocca" e devi terminare il processo mysql (descritto sopra con processlist;)


0

Nel mio caso, stavo eseguendo una query anomala per correggere i dati. Se blocchi le tabelle nella tua query, non dovrai occuparti del timeout di blocco:

LOCK TABLES `customer` WRITE;
update customer set account_import_id = 1;
UNLOCK TABLES;

Questa probabilmente non è una buona idea per un uso normale.

Per maggiori informazioni, consultare: Manuale di riferimento di MySQL 8.0


0

Mi sono imbattuto in questo avendo 2 connessioni DBAL Doctrine, una delle quali non transazionali (per i registri importanti), sono destinate a funzionare in parallelo non dipendono l'una dall'altra.

CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery()
)

I miei test di integrazione sono stati inseriti in transazioni per il rollback dei dati dopo molto test.

beginTransaction()
CodeExecution(
    TransactionConnectionQuery()
    TransactionlessConnectionQuery() // CONFLICT
)
rollBack()

La mia soluzione era disabilitare la transazione di wrapping in quei test e ripristinare i dati del db in un altro modo.


-4

Ho avuto lo stesso errore, anche se stavo aggiornando solo una tabella con una voce, ma dopo aver riavviato mysql, è stato risolto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.