Risolto il problema con “Timeout attesa blocco bloccato; provare a riavviare la transazione "per una tabella Mysql" bloccata "?


131

Da uno script ho inviato una query come questa migliaia di volte al mio database locale:

update some_table set some_column = some_value

Ho dimenticato di aggiungere la parte where, quindi la stessa colonna è stata impostata sullo stesso valore per tutte le righe nella tabella e questo è stato fatto migliaia di volte e la colonna è stata indicizzata, quindi l'indice corrispondente è stato probabilmente aggiornato troppe volte .

Ho notato che qualcosa non andava, perché ci è voluto troppo tempo, quindi ho ucciso la sceneggiatura. Ho anche riavviato il mio computer da allora, ma qualcosa si è bloccato nella tabella, perché le query semplici richiedono molto tempo per l'esecuzione e quando provo a eliminare l'indice rilevante non riesce con questo messaggio:

Lock wait timeout exceeded; try restarting transaction

È una tabella innodb, quindi la transazione bloccata è probabilmente implicita. Come posso risolvere questa tabella e rimuovere la transazione bloccata da essa?


3
Qual è l'output di SHOW FULL PROCESSLIST?
Wolph,

Mostra solo il comando SHOW FULL PROCESSLIST, nient'altro. È un database di sviluppo locale. Non ci sta funzionando. Ho ricevuto il messaggio di errore 'lock wait ..' sulla riga di comando quando ho provato a far cadere l'indice da lì.
Tom,

In tal caso probabilmente stai creando 2 connessioni separate in transazioni diverse che devono attendere l'una con l'altra.
Wolph,

Successivamente non ho creato alcuna transazione. Ho ucciso lo script, riavviato la macchina e ho effettuato l'accesso dalla riga di comando per guardarmi intorno. Nient'altro ha usato il database tranne il client della riga di comando mysql, quindi qualcosa deve essere stato bloccato nella tabella.
Tom,

Risposte:


143

Ho avuto un problema simile e l'ho risolto controllando i thread in esecuzione. Per vedere i thread in esecuzione utilizzare il seguente comando nell'interfaccia della riga di comando mysql:

SHOW PROCESSLIST;

Può anche essere inviato da phpMyAdmin se non si ha accesso all'interfaccia della riga di comando di mysql.
Verrà visualizzato un elenco di thread con ID e tempo di esecuzione corrispondenti, in modo da poter KILL i thread che impiegano troppo tempo per essere eseguiti. In phpMyAdmin avrai un pulsante per interrompere i thread usando KILL, se stai usando l'interfaccia della riga di comando usa semplicemente il comando KILL seguito dall'ID thread, come nell'esempio seguente:

KILL 115;

Ciò interromperà la connessione per il thread corrispondente.


36
PRENDI NOTA! Questo è stato menzionato da qualcuno su uno dei tanti thread SO relativi a questo problema: a volte il processo che ha bloccato la tabella appare come sospeso nella lista processi! Mi stavo strappando i capelli fino a quando non ho ucciso tutti i thread aperti nel database in questione, dormendo o no. Ciò ha finalmente sbloccato la tabella e lasciato eseguire la query di aggiornamento. Il commentatore ha menzionato qualcosa del tipo "A volte un thread MySQL blocca una tabella, quindi dorme mentre attende che accada qualcosa di non correlato a MySQL".
Eric L.,

(Ho aggiunto la mia risposta per approfondire quel frammento di pensiero qui , su una domanda correlata)
Eric L.

Questo mi ha aiutato. Ho avuto un paio di thread dormienti creati dalla funzionalità di gestione / query del database PHPStorm.
Ejaz,

Grande! Ho avuto un processo nascosto da 5 ore che ho potuto identificare e uccidere.
Aldo Paradiso,

2
questa non è una soluzione più di quanto non sia una nastratura del condotto su una ferita infetta. non stai affrontando il problema alla radice.
user2914191

55

Puoi controllare le transazioni attualmente in esecuzione con

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`

La tua transazione dovrebbe essere una delle prime, perché è la più vecchia dell'elenco. Ora prendi semplicemente il valore trx_mysql_thread_ide invialo il KILLcomando:

KILL 1234;

Se non sei sicuro di quale transazione è tua, ripeti la prima query molto spesso e vedi quali transazioni persistono.


Potrebbe essere necessario utilizzare l'account root per eseguire
quell'SQL

40

Controlla lo stato di InnoDB per i blocchi

SHOW ENGINE InnoDB STATUS;

Controlla le tabelle aperte di MySQL

SHOW OPEN TABLES WHERE In_use > 0;

Controlla le transazioni InnoDB in sospeso

SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`; 

Controlla la dipendenza dal blocco: cosa blocca cosa

SELECT * FROM `information_schema`.`innodb_locks`;

Dopo aver esaminato i risultati sopra, dovresti essere in grado di vedere cosa blocca cosa.

La causa principale del problema potrebbe essere anche nel tuo codice: controlla le funzioni correlate soprattutto per le annotazioni se usi JPA come Hibernate.

Ad esempio, come descritto qui , l'uso improprio della seguente annotazione potrebbe causare blocchi nel database:

@Transactional(propagation = Propagation.REQUIRES_NEW) 

4
Grazie mille! Running ha SELECT * FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.idrivelato il colpevole: il thread di blocco proveniva dal mio indirizzo IP ... Avevo dimenticato di chiudere una console di debug che avevo lasciato nel mezzo di una transazione ...
Elias Strehle

40

Questo ha cominciato a succedere a me quando la dimensione del mio database è cresciuta e stavo facendo molte transazioni su di esso.

La verità è che probabilmente c'è un modo per ottimizzare le tue query o il tuo DB, ma prova queste 2 query per risolvere il problema.

Esegui questo:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

E poi questo:

SET innodb_lock_wait_timeout = 5000; 

2
Link di riferimento: innodb_lock_wait_timeout
culix

1
Sto gestendo un database da 11 GB molto occupato. Questa è l'unica cosa che ha funzionato per me, grazie!
dongemus,

Ricorda solo di modificare i valori ai valori precedenti se non vuoi tenerli lì per sempre.
Ricardo Martins,

Ciò significa che alcuni dei miei utenti vivranno un'esperienza più lenta, giusto?
Arnold Roa,

9

Quando si stabilisce una connessione per una transazione, si acquisisce un blocco prima di eseguire la transazione. Se non riesci ad acquisire il lucchetto, allora prova per un po '. Se il blocco non è ancora ottenibile, viene generato l'errore del tempo di attesa superato. Il motivo per cui non è possibile acquisire un blocco è che non si sta chiudendo la connessione. Pertanto, quando si tenta di ottenere un blocco una seconda volta, non sarà possibile acquisire il blocco poiché la connessione precedente è ancora chiusa e si tiene il blocco.

Soluzione: chiudere la connessione o setAutoCommit(true)(secondo il proprio disegno) per rilasciare il blocco.


7

Riavvia MySQL, funziona benissimo.

MA attenzione che se una tale query è bloccata, c'è un problema da qualche parte:

  • nella tua query (carattere fuori posto, prodotto cartesiano, ...)
  • record molto numerosi da modificare
  • join o test complessi (MD5, sottostringhe LIKE %...%, ecc.)
  • problema di struttura dei dati
  • modello chiave esterna (blocco catena / anello)
  • dati errati

Come ha detto @syedrakib, funziona ma questa non è una soluzione di lunga durata per la produzione.

Attenzione: il riavvio può influire sui dati con uno stato incoerente.

Inoltre, puoi controllare come MySQL gestisce la tua query con la parola chiave EXPLAIN e vedere se è possibile qualcosa lì per accelerare la query (indici, test complessi, ...).


GRAZIE. non hai risolto il mio problema direttamente ma ho sofferto di blocchi di tabella ed è stato così male. Questo è l'unico post su Internet, il che mi porta all'idea di controllare le chiavi esterne. Così ho scoperto che la chiave della chiave primaria era 11 e le chiavi esterne 10. Non so come sia potuto accadere e perché tutto ha funzionato prima.
EscapeNetscape,

@EscapeNetscape sei il benvenuto, sono contento che questa piccola risposta ti abbia aiutato :)
Benj,

3

Vai ai processi in mysql.

Quindi posso vedere che l'attività è ancora funzionante.

Uccidi il processo particolare o attendi il completamento del processo.


7
Risolve il problema. Ma questa non può essere una soluzione per un server di produzione LIVE ... Come possiamo generare questa gestione dei deadlock? O come possiamo evitare che questo deadlock si verifichi?
Rakib,

1
beh, succede così che anche con query mysql PERFETTAMENTE ben formate e sfuggite PERFETTAMENTE che non sono nemmeno scritte dallo sviluppatore ma dall'interfaccia dei record attivi del framework, i problemi di timeout di attesa di blocco possono ANCORA accadere. Quindi non scrivo una query mysql corretta è un fattore qui.
Rakib,

1

Ho riscontrato lo stesso problema con una dichiarazione di "aggiornamento". La mia soluzione era semplicemente quella di eseguire le operazioni disponibili in phpMyAdmin per la tabella. Ho ottimizzato, svuotato e deframmentato la tabella (non in quell'ordine). Non è necessario eliminare la tabella e ripristinarla dal backup per me. :)


1
Potrebbe risolvere il problema. Ma doverlo fare ogni volta che si verifica un errore del genere non può essere una soluzione per un server di produzione LIVE ...... Come possiamo generare questa gestione dei deadlock? O come possiamo EVITARE che questo stallo si verifichi?
Rakib,

1

Ho avuto lo stesso problema. Penso che sia stato un problema di deadlock con SQL. È possibile forzare la chiusura del processo SQL da Task Manager. Se il problema persiste, riavvia il computer. Non è necessario eliminare la tabella e ricaricare i dati.


Risolve il problema. Ma questa non può essere una soluzione per un server di produzione LIVE ... Come possiamo generare questa gestione dei deadlock? O come possiamo evitare che questo deadlock si verifichi?
Rakib,

riavvia Apache e i suoi servizi (o almeno MySQL), non è necessario riavviare
Amjo

1

Ho avuto questo problema durante il tentativo di eliminare un determinato gruppo di record (utilizzando MS Access 2007 con una connessione ODBC a MySQL su un server Web). Solitamente eliminerei determinati record da MySQL e li sostituivo con quelli aggiornati (eliminando in cascata diversi record correlati, questo semplifica l'eliminazione di tutti i record correlati per una singola eliminazione di record).

Ho provato a eseguire le operazioni disponibili in phpMyAdmin per la tabella (ottimizzazione, svuotamento, ecc.), Ma stavo ottenendo l'autorizzazione necessaria per ricaricare l'errore quando ho provato a svuotare. Poiché il mio database si trova su un server Web, non sono riuscito a riavviare il database. Il ripristino da un backup non era un'opzione.

Ho provato a eseguire la query di eliminazione per questo gruppo di record sull'accesso mySQL cPanel sul Web. Ho ricevuto lo stesso messaggio di errore.

La mia soluzione: ho usato il MySQL Query Browser gratuito di Sun (Oracle) (che avevo precedentemente installato sul mio computer) e lì ho eseguito la query di eliminazione. Ha funzionato immediatamente, Problema risolto. Sono stato quindi in grado di eseguire nuovamente la funzione utilizzando lo script Access utilizzando la connessione ODBC Access a MySQL.


-2

Aggiustato.

Assicurati di non avere inserimenti di tipo di dati non corrispondenti nella query. Ho avuto un problema a cui stavo provando "dati agente browser utente" inVARCHAR(255) e ho avuto problemi con questo blocco quando l'ho modificato in TEXT(255)esso risolto.

Quindi molto probabilmente si tratta di una mancata corrispondenza del tipo di dati.


-151

Ho risolto il problema eliminando il tavolo e ripristinandolo dal backup.


20
Per inciso, questa risposta vince l'onore di essere la risposta "accettata" con il punteggio più basso di sempre di SO! 🏆
ashleedawg

1
Questa è anche la risposta con il punteggio più basso in generale
Bob Kerman,
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.