Bagaimana cara debug Batas waktu tunggu tunggu terlampaui di MySQL?

269

Dalam log kesalahan produksi, saya sesekali melihat:

SQLSTATE [HY000]: Kesalahan umum: 1205 Waktu tunggu tunggu kunci terlampaui; coba mulai kembali transaksi

Saya tahu permintaan mana yang mencoba mengakses database pada saat itu tetapi apakah ada cara untuk mengetahui permintaan mana yang memiliki kunci pada saat itu?

Matt McCormick
sumber
1
Saya sangat menyarankan semua orang untuk memberikan jawaban Eirik
kommradHomer

Jawaban:

261

Apa yang memberi ini adalah kata transaksi . Jelas dengan pernyataan bahwa kueri berusaha mengubah setidaknya satu baris dalam satu atau lebih tabel InnoDB.

Karena Anda tahu kueri, semua tabel yang diakses adalah kandidat untuk menjadi pelakunya.

Dari sana, Anda harus bisa berlari SHOW ENGINE INNODB STATUS\G

Anda harus dapat melihat tabel yang terpengaruh

Anda mendapatkan semua jenis Informasi Penguncian dan Mutex tambahan.

Berikut ini contoh dari salah satu klien saya:

mysql> show engine innodb status\G
*************************** 1. row ***************************
  Type: InnoDB
  Name:
Status:
=====================================
110514 19:44:14 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 4 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 9014315, signal count 7805377
Mutex spin waits 0, rounds 11487096053, OS waits 7756855
RW-shared spins 722142, OS waits 211221; RW-excl spins 787046, OS waits 39353
------------------------
LATEST FOREIGN KEY ERROR
------------------------
110507 21:41:35 Transaction:
TRANSACTION 0 606162814, ACTIVE 0 sec, process no 29956, OS thread id 1223895360 updating or deleting, thread declared inside InnoDB 499
mysql tables in use 1, locked 1
14 lock struct(s), heap size 3024, 8 row lock(s), undo log entries 1
MySQL thread id 3686635, query id 124164167 10.64.89.145 viget updating
DELETE FROM file WHERE file_id in ('6dbafa39-7f00-0001-51f2-412a450be5cc' )
Foreign key constraint fails for table `backoffice`.`attachment`:
,
  CONSTRAINT `attachment_ibfk_2` FOREIGN KEY (`file_id`) REFERENCES `file` (`file_id`)
Trying to delete or update in parent table, in index `PRIMARY` tuple:
DATA TUPLE: 17 fields;
 0: len 36; hex 36646261666133392d376630302d303030312d353166322d343132613435306265356363; asc 6dbafa39-7f00-0001-51f2-412a450be5cc;; 1: len 6; hex 000024214f7e; asc   $!O~;; 2: len 7; hex 000000400217bc; asc    @   ;; 3: len 2; hex 03e9; asc   ;; 4: len 2; hex 03e8; asc   ;; 5: len 36; hex 65666635323863622d376630302d303030312d336632662d353239626433653361333032; asc eff528cb-7f00-0001-3f2f-529bd3e3a302;; 6: len 40; hex 36646234376337652d376630302d303030312d353166322d3431326132346664656366352e6d7033; asc 6db47c7e-7f00-0001-51f2-412a24fdecf5.mp3;; 7: len 21; hex 416e67656c73204e6f7720436f6e666572656e6365; asc Angels Now Conference;; 8: len 34; hex 416e67656c73204e6f7720436f6e666572656e6365204a756c7920392c2032303131; asc Angels Now Conference July 9, 2011;; 9: len 1; hex 80; asc  ;; 10: len 8; hex 8000124a5262bdf4; asc    JRb  ;; 11: len 8; hex 8000124a57669dc3; asc    JWf  ;; 12: SQL NULL; 13: len 5; hex 8000012200; asc    " ;; 14: len 1; hex 80; asc  ;; 15: len 2; hex 83e8; asc   ;; 16: len 4; hex 8000000a; asc     ;;

But in child table `backoffice`.`attachment`, in index `PRIMARY`, there is a record:
PHYSICAL RECORD: n_fields 6; compact format; info bits 0
 0: len 30; hex 36646261666133392d376630302d303030312d353166322d343132613435; asc 6dbafa39-7f00-0001-51f2-412a45;...(truncated); 1: len 30; hex 38666164663561652d376630302d303030312d326436612d636164326361; asc 8fadf5ae-7f00-0001-2d6a-cad2ca;...(truncated); 2: len 6; hex 00002297b3ff; asc   "   ;; 3: len 7; hex 80000040070110; asc    @   ;; 4: len 2; hex 0000; asc   ;; 5: len 30; hex 416e67656c73204e6f7720436f6e666572656e636520446f63756d656e74; asc Angels Now Conference Document;;

------------
TRANSACTIONS
------------
Trx id counter 0 620783814
Purge done for trx's n:o < 0 620783800 undo n:o < 0 0
History list length 35
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, process no 29956, OS thread id 1192212800
MySQL thread id 5341758, query id 189708501 127.0.0.1 lwdba
show innodb status
---TRANSACTION 0 620783788, not started, process no 29956, OS thread id 1196472640
MySQL thread id 5341773, query id 189708353 10.64.89.143 viget
---TRANSACTION 0 0, not started, process no 29956, OS thread id 1223895360
MySQL thread id 5341667, query id 189706152 10.64.89.145 viget
---TRANSACTION 0 0, not started, process no 29956, OS thread id 1227888960
MySQL thread id 5341556, query id 189699857 172.16.135.63 lwdba
---TRANSACTION 0 620781112, not started, process no 29956, OS thread id 1222297920
MySQL thread id 5341511, query id 189696265 10.64.89.143 viget
---TRANSACTION 0 620783736, not started, process no 29956, OS thread id 1229752640
MySQL thread id 5339005, query id 189707998 10.64.89.144 viget
---TRANSACTION 0 620783785, not started, process no 29956, OS thread id 1198602560
MySQL thread id 5337583, query id 189708349 10.64.89.145 viget
---TRANSACTION 0 620783469, not started, process no 29956, OS thread id 1224161600
MySQL thread id 5333500, query id 189708478 10.64.89.144 viget
---TRANSACTION 0 620781240, not started, process no 29956, OS thread id 1198336320
MySQL thread id 5324256, query id 189708493 10.64.89.145 viget
---TRANSACTION 0 617458223, not started, process no 29956, OS thread id 1195141440
MySQL thread id 736, query id 175038790 Has read all relay log; waiting for the slave I/O thread to update it
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
519878 OS file reads, 18962880 OS file writes, 13349046 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 6.25 writes/s, 4.50 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 1190, seg size 1192,
174800 inserts, 174800 merged recs, 54439 merges
Hash table size 35401603, node heap has 35160 buffer(s)
0.50 hash searches/s, 11.75 non-hash searches/s
---
LOG
---
Log sequence number 28 1235093534
Log flushed up to   28 1235093534
Last checkpoint at  28 1235091275
0 pending log writes, 0 pending chkp writes
12262564 log i/o's done, 3.25 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 18909316674; in additional pool allocated 1048576
Dictionary memory allocated 2019632
Buffer pool size   1048576
Free buffers       175763
Database pages     837653
Modified db pages  6
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 770138, created 108485, written 7795318
0.00 reads/s, 0.00 creates/s, 4.25 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread process no. 29956, id 1185823040, state: sleeping
Number of rows inserted 6453767, updated 4602534, deleted 3638793, read 388349505551
0.25 inserts/s, 1.25 updates/s, 0.00 deletes/s, 2.75 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

1 row in set, 1 warning (0.00 sec)

Anda harus mempertimbangkan untuk meningkatkan nilai waktu tunggu tunggu kunci untuk InnoDB dengan mengatur innodb_lock_wait_timeout , standarnya adalah 50 detik

mysql> show variables like 'innodb_lock_wait_timeout';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+
1 row in set (0.01 sec)

Anda dapat mengaturnya ke nilai yang lebih tinggi /etc/my.cnfsecara permanen dengan baris ini

[mysqld]
innodb_lock_wait_timeout=120

dan mulai kembali mysql. Jika Anda tidak dapat memulai ulang mysql saat ini, jalankan ini:

SET GLOBAL innodb_lock_wait_timeout = 120; 

Anda juga bisa mengaturnya selama durasi sesi Anda

SET innodb_lock_wait_timeout = 120; 

diikuti oleh kueri Anda

RolandoMySQLDBA
sumber
5
Untuk InnoDB bawaan, innodb_lock_wait_timeoutvariabel hanya dapat ditetapkan saat startup server. Untuk Plugin InnoDB, dapat diatur saat startup atau diubah saat runtime, dan memiliki nilai global dan sesi.
Timo Huovinen
1
Hai @rolandomysqldba, bisakah Anda memberi saran kepada saya tentang postingan saya ini: stackoverflow.com/questions/18267565/…
Manish Sapkal
2
Saya mendapatkan kesalahan ini ketika mencoba menjalankan permintaan pertama:SQL Error (1064): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '\G' at line 1
Iulian Onofrei
1
@Pacerier Setiap kali mysqld dimulai ulang, Anda harus menjalankan SET GLOBAL innodb_lock_wait_timeout = 120;lagi. Jika /etc/my.cnfmemiliki opsi, innodb_lock_wait_timeoutdiatur untuk Anda. Tidak semua orang memiliki hak SUPER untuk mengubahnya secara global untuk orang lain ( dev.mysql.com/doc/refman/5.6/en/… )
RolandoMySQLDBA
3
@IulianOnofrei, karakter \ G adalah fitur khusus dari baris perintah MySQL dan mengubah cara output ditampilkan. Untuk klien MySQL lainnya, gunakan saja titik koma biasa.
thenickdude
83

Seperti seseorang yang disebutkan dalam salah satu dari banyak utas SO mengenai masalah ini: Kadang-kadang proses yang telah mengunci tabel muncul sebagai tidur di daftar proses! Saya mencabut rambut saya sampai saya membunuh semua utas tidur yang terbuka di database yang dimaksud (tidak ada yang aktif saat itu). Yang akhirnya membuka kunci tabel dan membiarkan kueri pembaruan berjalan.

Komentator mengatakan sesuatu yang mirip dengan "Kadang-kadang utas MySQL mengunci tabel, lalu tidur ketika menunggu sesuatu yang tidak berhubungan dengan MySQL terjadi."

Setelah meninjau kembali show engine innodb statuslog (setelah saya melacak klien yang bertanggung jawab untuk kunci), saya melihat utas yang macet tersebut tercantum di bagian paling bawah daftar transaksi, di bawah kueri aktif yang akan kesalahan keluar karena kunci beku:

------------------
---TRANSACTION 2744943820, ACTIVE 1154 sec(!!)
2 lock struct(s), heap size 376, 2 row lock(s), undo log entries 1
MySQL thread id 276558, OS thread handle 0x7f93762e7710, query id 59264109 [ip] [database] cleaning up
Trx read view will not see trx with id >= 2744943821, sees < 2744943821

(tidak yakin apakah pesan "Trx read view" terkait dengan kunci yang dibekukan, tetapi tidak seperti transaksi aktif lainnya, yang ini tidak muncul dengan kueri yang dikeluarkan dan sebaliknya mengklaim transaksi tersebut adalah "pembersihan," namun memiliki banyak kunci baris)

Moral dari cerita ini adalah bahwa transaksi dapat aktif meskipun utas sedang tidur.

Eric L.
sumber
2
saya tidak bisa mengatakan Anda menyelamatkan hidup saya, tetapi Anda menetapkan pikiran saya pada perdamaian pasti. Membaca jawaban Anda, saya menemukan utas menyeramkan yang aktif selama 3260 detik, dan tidak muncul di mana pun. setelah membunuhnya, semua masalah saya terpecahkan!
kommradHomer
Ini masalah saya. Transaksi tidur dengan waktu 20.000 detik yang mencegah Delayed Job dalam aplikasi Rails berjalan dengan benar. Terima kasih @Eirik
bigtex777
Adakah yang tahu mengapa transaksi tidur tidak terbunuh? Seperti, apakah ada batas waktu yang dapat Anda atur agar transaksi harus selesai?
patrickdavey
1
Perintah lain yang mungkin berguna dalam pencarian Anda untuk mengunci transaksi: show processlist;untuk menampilkan daftar lengkap dari proses yang sedang dieksekusi, yang bagus karena ini adalah versi kental dari show engine innodb status\g. Juga, jika db Anda menggunakan instance Amazon RDS, Anda dapat menggunakannya CALL mysql.rds_kill(<thread_id>);untuk mematikan utas. Ini memiliki izin yang lebih tinggi, saya pikir, karena memungkinkan saya untuk membunuh lebih banyak proses daripada yang biasa kill <thread_id>;- perhatikan ini harus dijalankan dalam MySQL CLI
nickang
1
Adakah yang punya sumber untuk ini - mungkin halaman dokumentasi yang menyatakan kunci ditempatkan sebelum fase COMMIT? Saya tidak dapat menemukan apa-apa, meskipun melihat masalah yang tepat ini dan sedang diselesaikan dengan membunuh utas tidur yang memegang kunci.
Erin Schoonover
42

Karena popularitas MySQL, tidak ada mengherankan waktu tunggu Lock melebihi; coba mulai kembali pengecualian transaksi mendapat begitu banyak perhatian pada SO.

Semakin banyak pertengkaran yang Anda miliki, semakin besar peluang kebuntuan, yang akan diselesaikan oleh mesin DB dengan memadamkan salah satu transaksi yang menemui jalan buntu. Juga, transaksi jangka panjang yang telah memodifikasi (misalnya UPDATEatau DELETE) sejumlah besar entri (yang mengambil kunci untuk menghindari anomali tulis-kotor seperti yang dijelaskan dalam buku Java Persistence Kinerja Tinggi ) lebih cenderung menimbulkan konflik dengan transaksi lainnya.

Meskipun InnoDB MVCC, Anda masih dapat meminta kunci eksplisit menggunakan FOR UPDATEklausa . Namun, tidak seperti DB populer lainnya (Oracle, MSSQL, PostgreSQL, DB2), MySQL menggunakan REPEATABLE_READsebagai tingkat isolasi default .

Sekarang, kunci yang Anda peroleh (baik dengan memodifikasi baris atau menggunakan penguncian eksplisit), ditahan selama durasi transaksi yang sedang berjalan. Jika Anda ingin penjelasan yang baik tentang perbedaan antara REPEATABLE_READdan READ COMMITTEDdalam hal penguncian, silakan baca artikel Percona ini .

Dalam REPEATABLE READ setiap kunci yang diperoleh selama suatu transaksi ditahan selama durasi transaksi.

Di READ COMMITTED, kunci yang tidak cocok dengan pemindaian dilepaskan setelah PERNYATAAN selesai.

...

Ini berarti bahwa dalam READ COMMITTED, transaksi lain bebas untuk memperbarui baris yang tidak dapat mereka perbarui (dalam REPEATABLE READ) setelah pernyataan UPDATE selesai.

Oleh karena itu: Semakin ketat tingkat isolasi ( REPEATABLE_READ, SERIALIZABLE) semakin besar kemungkinan kebuntuan. Ini bukan masalah "per se", ini adalah trade-off.

Anda bisa mendapatkan hasil yang sangat baik READ_COMMITED, karena Anda memerlukan pencegahan pembaruan tingkat aplikasi yang hilang saat menggunakan transaksi logis yang menjangkau beberapa permintaan HTTP. The penguncian optimis pendekatan target hilang update yang mungkin terjadi bahkan jika Anda menggunakan SERIALIZABLEtingkat isolasi sementara mengurangi anggapan kunci dengan memungkinkan Anda untuk menggunakan READ_COMMITED.

Vlad Mihalcea
sumber
4
Apakah kunci tunggu tunggu berbeda dengan kebuntuan? Misalnya jika satu utas memegang kunci selama 60 detik untuk alasan yang sah maka batas waktu tunggu kunci dapat terjadi. Apakah tidak benar bahwa jika memang ada kebuntuan, MySQL akan mendeteksi ini dan membunuh transaksi secara instan dan ini tidak terkait dengan penguncian waktu tunggu tunggu?
ColinM
1
Kamu benar. DB mendeteksi dead-lock setelah batas waktu dan membunuh satu proses menunggu, sehingga satu transaksi menang sementara yang lain gagal. Tetapi semakin lama Anda memegang kunci semakin skalabilitas aplikasi. Bahkan jika Anda tidak mengalami deadlock, Anda masih akan meningkatkan bagian serializable dari perilaku runtime aplikasi Anda.
Vlad Mihalcea
19

Sebagai catatan, pengecualian waktu tunggu tunggu kunci terjadi juga ketika ada jalan buntu dan MySQL tidak dapat mendeteksinya, jadi waktu itu hanya habis. Alasan lain mungkin adalah permintaan yang berjalan sangat lama, yang lebih mudah untuk diselesaikan / diperbaiki, namun, dan saya tidak akan menjelaskan kasus ini di sini.

MySQL biasanya dapat menangani kebuntuan jika mereka dibangun "dengan benar" dalam dua transaksi. MySQL kemudian hanya membunuh / mengembalikan satu transaksi yang memiliki kunci lebih sedikit (kurang penting karena akan berdampak lebih sedikit pada baris) dan memungkinkan yang lainnya menyelesaikan.

Sekarang, misalkan ada dua proses transaksi A dan B dan 3:

Process A Transaction 1: Locks X
Process B Transaction 2: Locks Y
Process A Transaction 3: Needs Y => Waits for Y
Process B Transaction 2: Needs X => Waits for X
Process A Transaction 1: Waits for Transaction 3 to finish

(see the last two paragraph below to specify the terms in more detail)

=> deadlock 

Ini adalah setup yang sangat disayangkan karena MySQL tidak dapat melihat ada jalan buntu (membentang dalam 3 transaksi). Jadi yang dilakukan MySQL adalah ... tidak ada apa-apa! Itu hanya menunggu, karena tidak tahu harus berbuat apa. Ia menunggu hingga kunci yang diperoleh pertama melebihi batas waktu (Proses A Transaksi 1: Kunci X), maka ini akan membuka blokir Kunci X, yang membuka kunci Transaksi 2 dll.

Seni adalah untuk mencari tahu apa (permintaan mana) yang menyebabkan kunci pertama (Kunci X). Anda akan dapat dengan mudah melihat ( show engine innodb status) bahwa Transaksi 3 menunggu Transaksi 2, tetapi Anda tidak akan melihat transaksi Transaksi 2 mana yang menunggu (Transaksi 1). MySQL tidak akan mencetak kunci atau kueri apa pun yang terkait dengan Transaksi 1. Satu-satunya petunjuk adalah bahwa di bagian paling bawah daftar transaksi (dari show engine innodb statushasil cetak), Anda akan melihat Transaksi 1 tampaknya tidak melakukan apa-apa (tetapi sebenarnya menunggu Transaksi 3 sampai selesai).

Teknik cara menemukan kueri SQL mana yang menyebabkan kunci (Kunci X) diberikan untuk transaksi tertentu yang menunggu dijelaskan di sini Tracking MySQL query history in long running transactions

Jika Anda bertanya-tanya apa proses dan transaksinya persis dalam contoh. Prosesnya adalah proses PHP. Transaksi adalah transaksi sebagaimana didefinisikan oleh innodb-trx-table . Dalam kasus saya, saya memiliki dua proses PHP, di masing-masing saya memulai transaksi secara manual. Bagian yang menarik adalah bahwa meskipun saya memulai satu transaksi dalam suatu proses, MySQL menggunakan secara internal sebenarnya dua transaksi terpisah (saya tidak tahu mengapa, mungkin beberapa dev MySQL dapat menjelaskan).

MySQL mengelola sendiri transaksinya secara internal dan memutuskan (dalam kasus saya) untuk menggunakan dua transaksi untuk menangani semua permintaan SQL yang berasal dari proses PHP (Proses A). Pernyataan bahwa Transaksi 1 sedang menunggu Transaksi 3 selesai adalah hal internal MySQL. MySQL "tahu" Transaksi 1 dan Transaksi 3 sebenarnya dipakai sebagai bagian dari satu permintaan "transaksi" (dari Proses A). Sekarang seluruh "transaksi" diblokir karena Transaksi 3 (bagian dari "transaksi") diblokir. Karena "transaksi" tidak dapat menyelesaikan Transaksi 1 (juga bagian dari "transaksi") ditandai sebagai tidak selesai juga. Inilah yang saya maksud dengan "Transaksi 1 menunggu Transaksi 3 selesai".

Tomas Bilka
sumber
14

Masalah besar dengan pengecualian ini adalah bahwa biasanya tidak dapat direproduksi dalam lingkungan pengujian dan kami tidak ada untuk menjalankan status mesin innodb ketika itu terjadi pada prod. Jadi di salah satu proyek saya memasukkan kode di bawah ini ke dalam catch block untuk pengecualian ini. Itu membantu saya mengetahui status mesin ketika pengecualian terjadi. Itu sangat membantu.

Statement st = con.createStatement();
ResultSet rs =  st.executeQuery("SHOW ENGINE INNODB STATUS");
while(rs.next()){
    log.info(rs.getString(1));
    log.info(rs.getString(2));
    log.info(rs.getString(3));
}
Maruthi
sumber
11

Lihatlah halaman manual pt-deadlock-loggerutilitas :

brew install percona-toolkit
pt-deadlock-logger --ask-pass server_name

Ini mengekstrak informasi dari yang engine innodb statusdisebutkan di atas dan juga dapat digunakan untuk membuat daemonyang berjalan setiap 30 detik.

Andrei Sura
sumber
3
alat ini sekarang menjadi bagian dari toolkit Percona
Brad Mace
Lockout timeout tidak sama dengan deadlock, khususnya innodb tidak menunjukkan informasi tentang deadlock karena tidak terdeteksi deadlock, jadi saya tidak berpikir pt-deadlock-logger dapat membantu.
Jay Paroline
Timeout
Andrei Sura
11

Mengekstrapolasi dari jawaban Rolando di atas, inilah yang memblokir permintaan Anda:

---TRANSACTION 0 620783788, not started, process no 29956, OS thread id 1196472640
MySQL thread id 5341773, query id 189708353 10.64.89.143 viget

Jika Anda perlu mengeksekusi kueri Anda dan tidak bisa menunggu yang lain berjalan, bunuh mereka menggunakan id utas MySQL:

kill 5341773 <replace with your thread id>

(dari dalam mysql, bukan shell, jelas)

Anda harus menemukan ID utas dari:

show engine innodb status\G

perintah, dan cari tahu yang mana yang memblokir database.

Ellert van Koperen
sumber
1
Bagaimana kamu tahu itu 5341773? Saya tidak melihat apa yang membedakan yang satu dari yang lain.
Wodin
Tidak, itu mungkin bukan threadID itu, itu adalah contoh. Anda harus menemukan ID utas dari perintah "show engine innodb status \ G", dan cari tahu yang mana yang memblokir basis data.
Ellert van Koperen
1
Terima kasih. Jadi dengan kata lain tidak ada cara untuk mengetahui yang mana tanpa mis membunuh mereka satu per satu?
Wodin
Dalam daftar transaksi Anda dapat melihat mana yang berjalan dan untuk berapa lama. Jadi tidak perlu membunuh mereka satu per satu, daftar itu biasanya memberi Anda ide yang cukup bagus tentang apa yang sedang terjadi.
Ellert van Koperen
10

Inilah yang akhirnya harus saya lakukan untuk mencari tahu apa "permintaan lain" yang menyebabkan masalah waktu tunggu kunci. Dalam kode aplikasi, kami melacak semua panggilan basis data yang tertunda pada utas terpisah yang didedikasikan untuk tugas ini. Jika ada panggilan DB yang lebih lama dari N-detik (bagi kami itu 30 detik) kami masuk:

-- Pending InnoDB transactions
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started; 

-- Optionally, log what transaction holds what locks
SELECT * FROM information_schema.innodb_locks;

Dengan di atas, kami dapat menentukan kueri bersamaan yang mengunci baris yang menyebabkan kebuntuan. Dalam kasus saya, itu adalah pernyataan INSERT ... SELECTyang tidak seperti SELECT biasa yang mengunci baris yang mendasarinya. Anda kemudian dapat mengatur ulang kode atau menggunakan isolasi transaksi yang berbeda seperti membaca tidak berkomitmen.

Semoga berhasil!

Slawomir
sumber
9

Kamu bisa memakai:

show full processlist

yang akan mencantumkan semua koneksi di MySQL dan status koneksi saat ini serta permintaan yang dieksekusi. Ada juga varian show processlist;yang lebih pendek yang menampilkan kueri terpotong serta statistik koneksi.

Gerrit Brink
sumber
-2

Aktifkan MySQL general.log (disk intensif) dan gunakan mysql_analyse_general_log.pl untuk mengekstrak transaksi yang sudah berjalan lama, misalnya dengan:

--min-durasi = nilai innodb_lock_wait_timeout Anda

Nonaktifkan general.log setelah itu.

mick
sumber