Làm thế nào để gỡ lỗi Khóa chờ quá thời gian chờ trên MySQL?


269

Trong nhật ký lỗi sản xuất của tôi, tôi thỉnh thoảng thấy:

SQLSTATE [HY000]: Lỗi chung: 1205 Đã hết thời gian chờ khóa; thử khởi động lại giao dịch

Tôi biết truy vấn nào đang cố truy cập cơ sở dữ liệu tại thời điểm đó nhưng có cách nào để tìm ra truy vấn nào có khóa tại thời điểm chính xác đó không?


1
Tôi thực sự khuyên mọi người nên trả lời câu hỏi của Eirik
kommradHomer

Câu trả lời:


261

Những gì cho đi này là giao dịch từ . Rõ ràng bằng tuyên bố rằng truy vấn đã cố gắng thay đổi ít nhất một hàng trong một hoặc nhiều bảng InnoDB.

Vì bạn biết truy vấn, tất cả các bảng được truy cập đều là ứng cử viên để trở thành thủ phạm.

Từ đó, bạn sẽ có thể chạy SHOW ENGINE INNODB STATUS\G

Bạn sẽ có thể thấy (các) bảng bị ảnh hưởng

Bạn nhận được tất cả các loại Thông tin khóa và Mutex bổ sung.

Đây là một mẫu từ một trong những khách hàng của tôi:

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)

Bạn nên xem xét tăng giá trị thời gian chờ khóa cho InnoDB bằng cách đặt innodb_lock_wait_timeout , mặc định là 50 giây

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

Bạn có thể đặt nó thành giá trị cao hơn /etc/my.cnfvĩnh viễn với dòng này

[mysqld]
innodb_lock_wait_timeout=120

và khởi động lại mysql. Nếu bạn không thể khởi động lại mysql tại thời điểm này, hãy chạy nó:

SET GLOBAL innodb_lock_wait_timeout = 120; 

Bạn cũng có thể chỉ đặt nó trong suốt thời gian của phiên của bạn

SET innodb_lock_wait_timeout = 120; 

theo sau là truy vấn của bạn


5
Đối với InnoDB tích hợp, innodb_lock_wait_timeoutbiến chỉ có thể được đặt khi khởi động máy chủ. Đối với Plugin InnoDB, nó có thể được đặt khi khởi động hoặc thay đổi khi chạy và có cả giá trị toàn cầu và phiên.
Timo Huovinen

1
Xin chào @rolandomysqldba, bạn có thể vui lòng cho tôi đề xuất về bài đăng này của tôi không: stackoverflow.com/questions/18267565/
mẹo

2
Tôi gặp lỗi này khi cố chạy truy vấn đầu tiên: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 Mỗi khi mysqld được khởi động lại, bạn phải chạy SET GLOBAL innodb_lock_wait_timeout = 120;lại. Nếu /etc/my.cnfcó tùy chọn, innodb_lock_wait_timeoutđược đặt cho bạn. Không phải ai cũng có đặc quyền SIÊU để thay đổi nó trên toàn cầu cho mọi người khác ( dev.mysql.com/doc/refman/5.6/en/ mẹo )
RolandoMyQueryDBA

3
@IulianOnofrei ký tự \ G là một tính năng đặc biệt của dòng lệnh MySQL và thay đổi cách hiển thị đầu ra. Đối với các máy khách MySQL khác, chỉ cần sử dụng dấu chấm phẩy thông thường.
thenickdude

83

Như ai đó đã đề cập trong một trong nhiều luồng SO liên quan đến vấn đề này: Đôi khi quá trình đã khóa bảng hiển thị như đang ngủ trong danh sách quy trình! Tôi đã xé tóc ra cho đến khi tôi giết tất cả các sợi ngủ đang mở trong cơ sở dữ liệu được đề cập (không có cái nào hoạt động vào thời điểm đó). Điều đó cuối cùng đã mở khóa bảng và để truy vấn cập nhật chạy.

Người bình luận đã nói điều gì đó giống như "Đôi khi một luồng MySQL khóa một bảng, sau đó ngủ trong khi nó chờ đợi một điều gì đó không liên quan đến MySQL xảy ra."

Sau khi xem xét lại show engine innodb statusnhật ký (một khi tôi đã theo dõi khách hàng chịu trách nhiệm về khóa), tôi nhận thấy chuỗi bị kẹt trong câu hỏi được liệt kê ở dưới cùng của danh sách giao dịch, bên dưới các truy vấn đang hoạt động sắp bị lỗi ra vì khóa đông lạnh:

------------------
---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

. khóa hàng)

Đạo đức của câu chuyện là một giao dịch có thể được kích hoạt mặc dù chủ đề đang ngủ.


2
Tôi không thể nói rằng bạn đã cứu cuộc đời tôi, nhưng bạn chắc chắn sẽ an tâm. Đọc câu trả lời của bạn, tôi thấy một chuỗi đáng sợ hoạt động trong 3260 giây và không hiển thị ở bất cứ đâu. Sau khi giết nó, mọi vấn đề của tôi đã được giải quyết!
kommradHomer

Đây là vấn đề của tôi. Một giao dịch ngủ với thời gian 20.000 giây đã ngăn Công việc bị trì hoãn trong ứng dụng Rails chạy đúng. Cảm ơn @Eirik
bigtex777

Bất cứ ý tưởng tại sao một giao dịch ngủ không bị giết chết? Giống như, có thời gian chờ bạn có thể thiết lập mà một giao dịch phải hoàn thành trong không?
patrickdavey

1
Các lệnh khác có thể hữu ích trong tìm kiếm khóa giao dịch của bạn: show processlist;để hiển thị danh sách đầy đủ các quy trình hiện đang được thực thi, điều này thật tuyệt vì đây là phiên bản thu gọn của show engine innodb status\g. Ngoài ra, nếu db của bạn nằm trong phiên bản Amazon RDS, bạn có thể sử dụng CALL mysql.rds_kill(<thread_id>);để tiêu diệt các luồng. Tôi nghĩ nó có quyền cao hơn, vì nó cho phép tôi giết nhiều tiến trình hơn đơn giản kill <thread_id>;- lưu ý những điều này nên được chạy trong MySQL CLI
nickang

1
Bất cứ ai cũng có một nguồn cho việc này - có thể một trang tài liệu nêu rõ các khóa được đặt trước giai đoạn CAM KẾT? Tôi không thể tìm thấy bất cứ điều gì, mặc dù nhìn thấy vấn đề chính xác này và nó đã được làm sáng tỏ bằng cách giết chết sợi ngủ đang giữ ổ khóa.
Erin Schoonover

42

Do sự phổ biến của MySQL, không có gì lạ khi thời gian chờ đợi của Lock vượt quá; hãy thử khởi động lại ngoại lệ giao dịch nhận được rất nhiều sự chú ý trên SO.

Bạn càng có nhiều sự tranh chấp, cơ hội bế tắc càng lớn, mà một công cụ DB sẽ giải quyết bằng cách hết thời gian một trong các giao dịch bị bế tắc. Ngoài ra, các giao dịch dài hạn đã sửa đổi (ví dụ UPDATEhoặc DELETE) một số lượng lớn các mục nhập (có khóa để tránh các bất thường viết bẩn như được giải thích trong sách Kiên trì Java hiệu suất cao ) có nhiều khả năng tạo ra xung đột với các giao dịch khác.

Mặc dù InnoDB MVCC, bạn vẫn có thể yêu cầu khóa rõ ràng bằng cách sử dụng FOR UPDATEmệnh đề . Tuy nhiên, không giống như các DB phổ biến khác (Oracle, MSSQL, PostgreSQL, DB2), MySQL sử dụng REPEATABLE_READlàm mức cô lập mặc định .

Bây giờ, các khóa mà bạn có được (bằng cách sửa đổi các hàng hoặc sử dụng khóa rõ ràng), được giữ trong suốt thời gian của giao dịch hiện đang chạy. Nếu bạn muốn giải thích rõ về sự khác biệt giữa REPEATABLE_READREAD COMMITTEDliên quan đến khóa, vui lòng đọc bài viết này của Percona .

Trong REPEATABLE READ, mọi khóa có được trong một giao dịch được giữ trong suốt thời gian giao dịch.

Trong READ CAM KẾT, các khóa không khớp với quá trình quét sẽ được giải phóng sau khi STATMENT hoàn thành.

...

Điều này có nghĩa là trong READ CAM KẾT, các giao dịch khác được tự do cập nhật các hàng mà họ không thể cập nhật (trong REPEATABLE READ) sau khi câu lệnh CẬP NHẬT hoàn thành.

Do đó: Mức cô lập ( REPEATABLE_READ, SERIALIZABLE) càng hạn chế thì khả năng bế tắc càng lớn. Đây không phải là một vấn đề "mỗi lần", đó là một sự đánh đổi.

Bạn có thể nhận được kết quả rất tốt với READ_COMMITED, vì bạn cần ngăn chặn cập nhật bị mất ở cấp ứng dụng khi sử dụng các giao dịch logic trải rộng trên nhiều yêu cầu HTTP. Phương pháp khóa lạc quan nhắm vào các bản cập nhật bị mất có thể xảy ra ngay cả khi bạn sử dụng SERIALIZABLEmức cô lập trong khi giảm sự tranh chấp khóa bằng cách cho phép bạn sử dụng READ_COMMITED.


4
Không khóa thời gian chờ khác với bế tắc? Ví dụ: nếu một luồng giữ khóa trong 60 giây vì lý do chính đáng thì thời gian chờ khóa có thể xảy ra. Có phải sự thật là nếu thực sự có bế tắc, MySQL sẽ phát hiện ra điều này và giết chết một giao dịch ngay lập tức và điều này không liên quan đến thời gian chờ khóa?
ColinM

1
Bạn đúng rồi. DB phát hiện khóa chết sau khi hết thời gian và giết chết một quy trình chờ, vì vậy một giao dịch sẽ thắng trong khi giao dịch khác thất bại. Nhưng bạn càng giữ khóa lâu thì ứng dụng càng có khả năng mở rộng. Ngay cả khi bạn không chạy vào các khóa chết, bạn vẫn sẽ tăng phần tuần tự hóa trong hành vi thời gian chạy ứng dụng của mình.
Vlad Mihalcea

19

Đối với bản ghi, ngoại lệ thời gian chờ khóa cũng xảy ra khi có bế tắc và MySQL không thể phát hiện ra, vì vậy nó chỉ hết thời gian. Một lý do khác có thể là một truy vấn chạy rất dài, tuy nhiên, việc giải quyết / sửa chữa dễ dàng hơn và tôi sẽ không mô tả trường hợp này ở đây.

MySQL thường có thể xử lý các bế tắc nếu chúng được xây dựng "đúng" trong hai giao dịch. Sau đó, MySQL chỉ giết / khôi phục một giao dịch sở hữu ít khóa hơn (ít quan trọng hơn vì nó sẽ tác động đến ít hàng hơn) và cho phép một giao dịch khác kết thúc.

Bây giờ, giả sử có hai quy trình A và B và 3 giao dịch:

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 

Đây là một thiết lập rất đáng tiếc vì MySQL không thể thấy có sự bế tắc (kéo dài trong 3 giao dịch). Vì vậy, những gì MySQL làm là ... không có gì! Nó chỉ chờ đợi, vì nó không biết phải làm gì. Nó đợi cho đến khi khóa thu được đầu tiên vượt quá thời gian chờ (Quá trình A Giao dịch 1: Khóa X), sau đó điều này sẽ bỏ chặn Khóa X, mở khóa Giao dịch 2, v.v.

Nghệ thuật là tìm ra cái gì (truy vấn nào) gây ra khóa đầu tiên (Khóa X). Bạn sẽ có thể dễ dàng thấy ( show engine innodb status) Giao dịch 3 chờ Giao dịch 2, nhưng bạn sẽ không thấy Giao dịch 2 nào đang chờ (Giao dịch 1). MySQL sẽ không in bất kỳ khóa hoặc truy vấn nào liên quan đến Giao dịch 1. Gợi ý duy nhất là ở cuối danh sách giao dịch (của show engine innodb statusbản in), bạn sẽ thấy Giao dịch 1 dường như không làm gì cả (nhưng thực tế đang chờ Giao dịch 3 để hoàn thành).

Kỹ thuật tìm cách truy vấn SQL nào khiến khóa (Khóa X) được cấp cho một giao dịch nhất định đang chờ được mô tả ở đây Tracking MySQL query history in long running transactions

Nếu bạn đang tự hỏi những gì quá trình và giao dịch là chính xác trong ví dụ. Quá trình này là một quá trình PHP. Giao dịch là một giao dịch theo định nghĩa của bảng innodb-trx . Trong trường hợp của tôi, tôi đã có hai quy trình PHP, trong mỗi lần tôi bắt đầu một giao dịch theo cách thủ công. Điều thú vị là mặc dù tôi đã bắt đầu một giao dịch trong một quy trình, nhưng thực tế MySQL đã sử dụng hai giao dịch riêng biệt (tôi không biết tại sao, có thể một số nhà phát triển MySQL có thể giải thích).

MySQL đang quản lý các giao dịch của riêng mình trong nội bộ và quyết định (trong trường hợp của tôi) sử dụng hai giao dịch để xử lý tất cả các yêu cầu SQL đến từ quy trình PHP (Quy trình A). Tuyên bố rằng Giao dịch 1 đang chờ Giao dịch 3 kết thúc là một điều nội bộ của MySQL. MySQL "biết" Giao dịch 1 và Giao dịch 3 thực sự được khởi tạo như một phần của một yêu cầu "giao dịch" (từ Quy trình A). Bây giờ toàn bộ "giao dịch" đã bị chặn vì Giao dịch 3 (một phần phụ của "giao dịch") đã bị chặn. Bởi vì "giao dịch" không thể kết thúc Giao dịch 1 (cũng là một phần phụ của "giao dịch") được đánh dấu là chưa hoàn thành. Đây là những gì tôi có nghĩa là "Giao dịch 1 chờ Giao dịch 3 kết thúc".


14

Vấn đề lớn với ngoại lệ này là nó thường không thể tái tạo trong môi trường thử nghiệm và chúng tôi không có mặt để chạy trạng thái động cơ innodb khi nó xảy ra trên prod. Vì vậy, trong một trong các dự án tôi đặt mã dưới đây vào một khối bắt cho ngoại lệ này. Điều đó giúp tôi nắm bắt tình trạng động cơ khi ngoại lệ xảy ra. Điều đó đã giúp rất nhiều.

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));
}

11

Hãy xem trang người đàn ông của pt-deadlock-loggertiện ích :

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

Nó trích xuất thông tin từ các engine innodb statusđề cập ở trên và nó cũng có thể được sử dụng để tạo ra một daemoncái chạy cứ sau 30 giây.


3
công cụ này hiện là một phần của bộ công cụ Percona
Brad Mace

Thời gian chờ khóa không giống như bế tắc, cụ thể là innodb không hiển thị bất kỳ thông tin nào về chúng vì chúng không được phát hiện bế tắc, vì vậy tôi không nghĩ pt-deadlock-logger là bất kỳ trợ giúp nào.
Jay Paroline

Thời gian chờ khóa và khóa chết có liên quan mặc dù - xem dev.mysql.com/doc/refman/5.7/en/innodb-deadlock-detection.html
Andrei Sura

11

Ngoại suy từ câu trả lời của Rolando ở trên, chính những điều này đang chặn truy vấn của bạn:

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

Nếu bạn cần thực hiện truy vấn của mình và không thể đợi người khác chạy, hãy tắt chúng bằng cách sử dụng id luồng của MySQL:

kill 5341773 <replace with your thread id>

(từ bên trong mysql, không phải vỏ, rõ ràng)

Bạn phải tìm ID luồng từ:

show engine innodb status\G

lệnh và tìm ra cái nào là cái đang chặn cơ sở dữ liệu.


1
Làm thế nào để bạn biết nó 5341773? Tôi không thấy cái gì phân biệt cái này với cái khác.
Wodin

Không, nó có lẽ không phải là threadID, nó là một ví dụ. Bạn phải tìm ID luồng từ lệnh "show engine innodb status \ G" và tìm ra cái nào là cái đang chặn cơ sở dữ liệu.
Ellert van Koperen

1
Cảm ơn. Vì vậy, nói cách khác, không có cách nào để biết đó là ai mà không cần giết từng người một?
Wodin

Trong danh sách các giao dịch, bạn có thể xem những giao dịch nào đang chạy và trong bao lâu. Vì vậy, không cần phải giết từng người một, danh sách đó thường cung cấp cho bạn một ý tưởng khá hay về những gì đang diễn ra.
Ellert van Koperen

10

Đây là những gì cuối cùng tôi đã phải làm để tìm ra "truy vấn khác" gây ra vấn đề thời gian chờ khóa. Trong mã ứng dụng, chúng tôi theo dõi tất cả các cuộc gọi cơ sở dữ liệu đang chờ xử lý trên một luồng riêng dành cho nhiệm vụ này. Nếu bất kỳ cuộc gọi DB nào mất nhiều thời gian hơn N giây (đối với chúng tôi là 30 giây), chúng tôi sẽ đăng nhập:

-- 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;

Với ở trên, chúng tôi có thể xác định chính xác các truy vấn đồng thời khóa các hàng gây ra bế tắc. Trong trường hợp của tôi, chúng là những câu nhưINSERT ... SELECT không giống như các CHỌN đơn giản khóa các hàng bên dưới. Sau đó, bạn có thể sắp xếp lại mã hoặc sử dụng cách ly giao dịch khác như đọc không cam kết.

Chúc may mắn!


9

Bạn có thể dùng:

show full processlist

sẽ liệt kê tất cả các kết nối trong MySQL và trạng thái kết nối hiện tại cũng như truy vấn đang được thực thi. Ngoài ra còn có một biến thể ngắn hơn show processlist;hiển thị truy vấn rút ngắn cũng như các số liệu thống kê kết nối.



-2

Kích hoạt MySQL general.log (chuyên sâu về đĩa) và sử dụng mysql_analyse_general_log.pl để trích xuất các giao dịch chạy dài, ví dụ như:

--min-thời gian = giá trị innodb_lock_wait_timeout của bạn

Vô hiệu hóa general.log sau đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.