Memperbaiki “Batas waktu tunggu tunggu melebihi; coba mulai kembali transaksi ”untuk tabel Mysql 'macet'?

131

Dari skrip saya mengirim permintaan seperti ini ribuan kali ke basis data lokal saya:

update some_table set some_column = some_value

Saya lupa menambahkan bagian di mana, jadi kolom yang sama ditetapkan ke nilai yang sama untuk semua baris dalam tabel dan ini dilakukan ribuan kali dan kolom diindeks, sehingga indeks yang sesuai mungkin diperbarui terlalu banyak kali .

Saya perhatikan ada sesuatu yang salah, karena terlalu lama, jadi saya membunuh naskahnya. Saya bahkan me-reboot komputer saya sejak itu, tetapi ada sesuatu yang macet di tabel, karena permintaan sederhana membutuhkan waktu yang sangat lama untuk dijalankan dan ketika saya mencoba menjatuhkan indeks yang relevan gagal dengan pesan ini:

Lock wait timeout exceeded; try restarting transaction

Ini adalah tabel innodb, jadi transaksi yang macet mungkin implisit. Bagaimana saya bisa memperbaiki tabel ini dan menghapus transaksi macet dari itu?

Tom
sumber
3
Apa output dari SHOW FULL PROCESSLIST?
Wolph
Ini hanya menunjukkan perintah PROWESI TAMPILKAN SHOW, tidak lain. Ini adalah database pengembangan lokal. Tidak ada yang berjalan di sana. Saya mendapat pesan kesalahan 'kunci tunggu ..' di baris perintah ketika saya mencoba menjatuhkan indeks dari sana.
Tom
Dalam hal ini Anda mungkin membuat 2 koneksi terpisah dalam transaksi berbeda yang harus menunggu satu sama lain.
Wolph
Saya tidak melakukan transaksi apa pun setelah itu. Saya membunuh skrip, me-reboot mesin dan masuk dari baris perintah untuk melihat-lihat. Tidak ada yang menggunakan database kecuali untuk klien baris perintah mysql, jadi pasti ada sesuatu yang macet di tabel.
Tom

Jawaban:

143

Saya memiliki masalah yang sama dan menyelesaikannya dengan memeriksa utas yang sedang berjalan. Untuk melihat utas yang sedang berjalan gunakan perintah berikut di antarmuka baris perintah mysql:

SHOW PROCESSLIST;

Itu juga dapat dikirim dari phpMyAdmin jika Anda tidak memiliki akses ke antarmuka baris perintah mysql.
Ini akan menampilkan daftar utas dengan id yang sesuai dan waktu eksekusi, sehingga Anda dapat MEMBUNUH utas yang terlalu banyak waktu untuk dieksekusi. Di phpMyAdmin Anda akan memiliki tombol untuk menghentikan utas dengan menggunakan KILL, jika Anda menggunakan antarmuka baris perintah gunakan saja perintah KILL diikuti oleh id utas, seperti dalam contoh berikut:

KILL 115;

Ini akan memutuskan koneksi untuk utas yang sesuai.

Mihai Crăiță
sumber
36
PERHATIKAN! Ini disebutkan oleh seseorang di salah satu dari sekian banyak thread SO mengenai masalah ini: Kadang-kadang proses yang telah mengunci tabel muncul sebagai tidur di daftar proses! Saya mencabuti rambut saya sampai saya membunuh semua utas yang terbuka di database yang bersangkutan, tidur atau tidak. Itu akhirnya membuka kunci tabel dan membiarkan kueri pembaruan berjalan. Komentator menyebutkan sesuatu seperti "Kadang-kadang utas MySQL mengunci sebuah tabel, lalu tidur ketika menunggu sesuatu yang tidak berhubungan dengan MySQL terjadi."
Eric L.
(Saya menambahkan jawaban saya sendiri untuk menyempurnakan pemikiran itu di sini , pada pertanyaan terkait)
Eric L.
Ini membantu saya. Saya punya beberapa utas tidur yang dibuat oleh fitur manajemen / permintaan basis data PHPStorm.
Ejaz
Bagus! Saya memiliki proses tersembunyi sejak 5 jam sehingga saya bisa mengidentifikasi dan membunuh.
Aldo Paradiso
2
ini bukan solusi lebih dari saluran yang menutupi luka yang terinfeksi adalah solusi. Anda tidak mengatasi masalah root yang mendasarinya.
user2914191
55

Anda dapat memeriksa transaksi yang sedang berjalan dengan

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

Transaksi Anda harus menjadi yang pertama, karena ini adalah yang tertua dalam daftar. Sekarang ambil saja nilai dari trx_mysql_thread_iddan kirimkan KILLperintah:

KILL 1234;

Jika Anda tidak yakin transaksi mana yang menjadi milik Anda, ulangi permintaan pertama dengan sangat sering dan lihat transaksi mana yang tetap ada.

nlsrchtr
sumber
Anda mungkin perlu menggunakan akun root untuk menjalankan SQL itu untuk melihat transaksi mana yang sebenarnya menghalangi orang lain dari mengakses tabel
tom10271
40

Periksa status InnoDB untuk kunci

SHOW ENGINE InnoDB STATUS;

Periksa tabel terbuka MySQL

SHOW OPEN TABLES WHERE In_use > 0;

Periksa transaksi InnoDB yang tertunda

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

Periksa ketergantungan kunci - apa yang menghalangi apa

SELECT * FROM `information_schema`.`innodb_locks`;

Setelah menyelidiki hasil di atas, Anda seharusnya bisa melihat apa yang mengunci apa.

Penyebab utama masalah mungkin ada dalam kode Anda juga - silakan periksa fungsi terkait terutama untuk anotasi jika Anda menggunakan JPA seperti Hibernate.

Misalnya, seperti dijelaskan di sini , penyalahgunaan anotasi berikut dapat menyebabkan kunci dalam database:

@Transactional(propagation = Propagation.REQUIRES_NEW) 
martoncsukas
sumber
4
Terima kasih banyak! Running SELECT * FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.idmengungkapkan penyebabnya: Utas penguncian berasal dari alamat IP saya ... Saya lupa menutup konsol debug yang saya tinggalkan di tengah transaksi ...
Elias Strehle
40

Ini mulai terjadi pada saya ketika ukuran basis data saya bertambah dan saya melakukan banyak transaksi.

Sebenarnya mungkin ada beberapa cara untuk mengoptimalkan kueri atau DB Anda, tetapi cobalah 2 kueri ini untuk menyelesaikan masalah.

Jalankan ini:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

Dan kemudian ini:

SET innodb_lock_wait_timeout = 5000; 
Max D
sumber
2
Tautan referensi: innodb_lock_wait_timeout
culix
1
Saya menjalankan database 11GB yang sangat sibuk. Ini adalah satu-satunya hal yang berhasil bagi saya, terima kasih!
dongemus
Ingatlah untuk mengubah nilai ke nilai sebelumnya jika Anda tidak ingin menyimpannya selamanya.
Ricardo Martins
Ini berarti bahwa beberapa pengguna saya akan memiliki pengalaman yang lebih lambat, bukan?
Arnold Roa
9

Ketika Anda membuat koneksi untuk transaksi, Anda mendapatkan kunci sebelum melakukan transaksi. Jika tidak dapat memperoleh kunci, maka Anda mencoba beberapa saat. Jika kunci masih tidak dapat diperoleh, maka waktu tunggu kunci yang terlampaui dilemparkan. Mengapa Anda tidak dapat memperoleh kunci adalah karena Anda tidak menutup koneksi. Jadi, ketika Anda mencoba untuk mendapatkan kunci kedua kalinya, Anda tidak akan dapat memperoleh kunci karena koneksi Anda sebelumnya masih tertutup dan memegang kunci.

Solusi: tutup koneksi atau setAutoCommit(true)(sesuai desain Anda) untuk melepaskan kunci.

pengguna3388324
sumber
7

Restart MySQL, ini berfungsi dengan baik.

TAPI waspadalah bahwa jika permintaan seperti itu macet, ada masalah di suatu tempat:

  • dalam kueri Anda (char salah tempat, produk cartesian, ...)
  • sangat banyak catatan untuk diedit
  • gabungan atau tes yang kompleks (MD5, substring LIKE %...%,, dll.)
  • masalah struktur data
  • model kunci asing (penguncian rantai / loop)
  • data salahindeks

Seperti yang dikatakan @syedrakib, ini bekerja tetapi ini bukan solusi jangka panjang untuk produksi.

Hati-hati: melakukan restart dapat memengaruhi data Anda dengan kondisi tidak konsisten.

Anda juga dapat memeriksa bagaimana MySQL menangani kueri Anda dengan kata kunci EXPLAIN dan melihat apakah ada sesuatu yang mungkin di sana untuk mempercepat kueri (indeks, tes kompleks, ...).

Benj
sumber
TERIMA KASIH. Anda tidak memecahkan masalah saya secara langsung tetapi saya menderita kunci meja dan itu sangat buruk. Itulah satu-satunya posting ob seluruh internet, yang membawa saya pada ide untuk memeriksa kunci asing. Jadi saya menemukan bahwa kunci kunci primer adalah 11 dan kunci asing 10. Saya tidak tahu bagaimana itu bisa terjadi dan mengapa semuanya bekerja sebelumnya.
EscapeNetscape
@EscapeNetscape sama-sama, saya senang jawaban kecil ini membantu Anda :)
Benj
3

Proses goto di mysql.

Jadi bisa melihat ada tugas yang masih berfungsi.

Bunuh proses tertentu atau tunggu sampai proses selesai.

Shemeer M Ali
sumber
7
Ini memecahkan masalah. Tapi ini tidak bisa menjadi solusi untuk server produksi LANGSUNG ...... Bagaimana kita bisa menghasilkan penanganan kebuntuan ini? Atau bagaimana kita bisa MENGHINDARI jalan buntu ini terjadi?
Rakib
1
baik, kebetulan bahwa bahkan dengan kueri sempurna mysql yang terbentuk dengan sempurna dan sempurna yang bahkan tidak ditulis oleh pengembang tetapi oleh antarmuka catatan aktif dari kerangka kerja, masalah waktu tunggu tunggu kunci MASIH dapat terjadi. Jadi saya tidak menulis permintaan mysql yang tepat adalah faktor di sini.
Rakib
1

Saya mengalami masalah yang sama dengan pernyataan "pembaruan". Solusi saya adalah menjalankan melalui operasi yang tersedia di phpMyAdmin untuk tabel. Saya mengoptimalkan, memerah dan mendefragmentasi tabel (tidak dalam urutan itu). Tidak perlu menjatuhkan meja dan mengembalikannya dari cadangan untuk saya. :)

Bocah Sains
sumber
1
Mungkin memecahkan masalah. Tetapi harus melakukan ini setiap kali kesalahan tersebut terjadi tidak dapat menjadi solusi untuk server produksi LANGSUNG ...... Bagaimana kita bisa menghasilkan penanganan kebuntuan ini? Atau bagaimana kita bisa MENGHINDARI jalan buntu ini terjadi?
Rakib
1

Saya memiliki masalah yang sama. Saya pikir itu masalah kebuntuan dengan SQL. Anda bisa langsung menutup proses SQL dari Task Manager. Jika itu tidak memperbaikinya, cukup restart komputer Anda. Anda tidak perlu menjatuhkan tabel dan memuat ulang data.

Kriver
sumber
Ini memecahkan masalah. Tapi ini tidak bisa menjadi solusi untuk server produksi LANGSUNG ...... Bagaimana kita bisa menghasilkan penanganan kebuntuan ini? Atau bagaimana kita bisa MENGHINDARI jalan buntu ini terjadi?
Rakib
restart Apache dan layanannya (atau setidaknya MySQL), tidak perlu reboot
Amjo
1

Saya punya masalah ini ketika mencoba untuk menghapus kelompok catatan tertentu (menggunakan MS Access 2007 dengan koneksi ODBC ke MySQL di server web). Biasanya saya akan menghapus catatan tertentu dari MySQL kemudian ganti dengan catatan yang diperbarui (kaskade menghapus beberapa catatan terkait, aliran ini menghapus semua catatan terkait untuk satu penghapusan catatan tunggal).

Saya mencoba menjalankan melalui operasi yang tersedia di phpMyAdmin untuk tabel (optimalkan, flush, dll), tetapi saya mendapatkan izin yang diperlukan untuk kesalahan RELOAD ketika saya mencoba untuk menyiram. Karena database saya ada di server web, saya tidak bisa memulai kembali database. Mengembalikan dari cadangan bukanlah opsi.

Saya mencoba menjalankan kueri penghapusan untuk grup rekaman ini di akses mySQL cPanel di web. Mendapat pesan kesalahan yang sama.

Solusi saya: Saya menggunakan Browser Kueri MySQL gratis dari Sun (yang saya instal di komputer saya) dan menjalankan query delete di sana. Itu langsung bekerja, Masalah terpecahkan. Saya kemudian dapat sekali lagi melakukan fungsi menggunakan skrip Access menggunakan ODBC Access ke koneksi MySQL.

Mike Lane
sumber
-2

Memperbaikinya.

Pastikan Anda tidak memasukkan data yang tidak cocok dengan kueri. Saya mengalami masalah ketika saya mencoba "data agen peramban pengguna" VARCHAR(255)dan mengalami masalah dengan kunci ini namun ketika saya mengubahnyaTEXT(255) memperbaikinya.

Jadi kemungkinan besar itu adalah ketidakcocokan tipe data.

Hiren Raj
sumber
-151

Saya memecahkan masalah dengan menjatuhkan meja dan mengembalikannya dari cadangan.

Tom
sumber
20
Kebetulan, jawaban ini memenangkan kehormatan sebagai Jawaban "Diterima" Paling Rendah Skor SO-nya! 🏆
ashleedawg
1
Ini juga jawaban dengan skor terendah secara umum
Bob Kerman