2009-11-06 32 views
6

Tôi cho rằng vấn đề này áp dụng cho deadlocks, live-locks hoặc chỉ khóa thời gian chờ chờ.Làm cách nào để giải quyết vấn đề khóa trong MySQL?

Tôi đang cố gắng tìm ra truy vấn nào gây ra khóa đang ngăn truy vấn khác thực thi. Oracle có (nếu bộ nhớ phục vụ) một bảng LOCK mà bạn có thể tham gia vào chính nó để xác định truy vấn nào đang khóa những người khác. Tôi cần một cách để thực hiện điều này trong MySQL.

Kịch bản là chúng tôi có các công việc lâu dài đôi khi tạo giao dịch lồng nhau cập nhật trường tiến trình. Bằng cách đó, chúng tôi không làm mất giao dịch của tác phẩm trong khi vẫn thông báo cho người dùng về tiến độ (tức là hoàn thành phần trăm). Giao dịch lồng nhau đôi khi ném một ngoại lệ thời gian chờ khóa.

Điều này rất kỳ quặc, vì không công việc nào khác nên viết - hoặc thậm chí là đọc - từ bảng công việc. Chọn lọc thông qua nhật ký SQL thô xác nhận điều này. Dưới đây là phần giao dịch từ SHOW ENGINE InnoDB TÌNH TRẠNG:

------------ 
TRANSACTIONS 
------------ 
Trx id counter 0 479427 
Purge done for trx's n:o < 0 479425 undo n:o < 0 0 
History list length 19 
LIST OF TRANSACTIONS FOR EACH SESSION: 
---TRANSACTION 0 0, not started, OS thread id 3192 
MySQL thread id 31, query id 17417 localhost 127.0.0.1 root 
show engine innodb status 
---TRANSACTION 0 0, not started, OS thread id 3776 
MySQL thread id 29, query id 13062 localhost 127.0.0.1 root 
---TRANSACTION 0 479190, not started, OS thread id 2540 
MySQL thread id 23, query id 16103 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479422, not started, OS thread id 2536 
MySQL thread id 19, query id 17338 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479194, not started, OS thread id 2528 
MySQL thread id 20, query id 16103 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479189, not started, OS thread id 2776 
MySQL thread id 22, query id 16103 localhost 127.0.0.1 testuser 
---TRANSACTION 0 479426, ACTIVE 3 sec, OS thread id 2544 starting index read 
mysql tables in use 1, locked 1 
LOCK WAIT 2 lock struct(s), heap size 320, 1 row lock(s) 
MySQL thread id 18, query id 17414 localhost 127.0.0.1 testuser Updating 
update Job set progress=0.000482780829770491 where id=28 
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED: 
RECORD LOCKS space id 0 page no 23927 n bits 72 index "PRIMARY" of table "test"."job" trx id 0 479426 lock_mode X locks rec but not gap waiting 
Record lock, heap no 5 PHYSICAL RECORD: n_fields 12; compact format; info bits 0 
0: len 8; hex 000000000000001c; asc   ;; 1: len 6; hex 0000000750bf; asc  P ;; 2: len 7; hex 0000005d4d2aeb; asc ]M* ;; 3: len 8; hex 0000000000000005; asc   ;; 4: len 8; hex 0000000000000004; asc   ;; 5: len 8; hex 0000000000000006; asc   ;; 6: len 1; hex 49; asc I;; 7: len 14; hex 800000000000000002749e0e51a6; asc   t Q ;; 8: len 30; hex 3c6d61703e0a20203c656e7472793e0a202020203c737472696e673e7061; asc <map> <entry>  <string>pa;...(truncated); 9: len 8; hex 80001245d33e7e3c; asc E >~<;; 10: SQL NULL; 11: SQL NULL; 

------------------ 
---TRANSACTION 0 479418, ACTIVE 31 sec, OS thread id 960 
14 lock struct(s), heap size 1024, 8 row lock(s), undo log entries 3 
MySQL thread id 21, query id 17404 localhost 127.0.0.1 testuser 

Nó xuất hiện rõ ràng rằng chỉ có hai giao dịch, và đó là một trong những 14 ổ khóa của giao dịch 479.418 chặn giao dịch 479426. Tôi rất thích biết những gì truy vấn vi phạm là. Bất kỳ ý tưởng? Thậm chí liệt kê 14 khóa và các truy vấn gây ra chúng sẽ là tuyệt vời.

Cảm ơn!

Trả lời

0

Trong phiên họp của msql> hãy thử

12.5.5.31. HIỂN THỊ processlist Cú pháp

HIỂN THỊ [FULL] processlist

HIỂN THỊ processlist cho bạn mà đề đang chạy. Bạn cũng có thể lấy thông tin này từ bảng INFORMATION_SCHEMA PROCESSLIST hoặc lệnh mysqladmin processlist. Nếu bạn có đặc quyền PROCESS, bạn có thể xem tất cả các chủ đề. Nếu không, bạn chỉ có thể xem các chủ đề của riêng bạn (có nghĩa là, các luồng được kết hợp với tài khoản MySQL mà bạn đang sử dụng). Nếu bạn không sử dụng từ khóa ĐẦY ĐỦ, chỉ 100 ký tự đầu tiên của mỗi câu lệnh được hiển thị trong trường Thông tin.

+1

Tuyên bố này chỉ cho bạn biết những gì đang thực hiện tại thời điểm nó được chạy. Do quy trình làm việc của tôi đang thực hiện hàng trăm câu lệnh một giây, các bản ghi SQL có lẽ thích hợp hơn để gỡ lỗi vấn đề này. –

0

Một tùy chọn là bật general query log, sẽ ghi lại tất cả các câu lệnh chạy trên mysql. Chỉ cần cẩn thận nó không ăn tất cả không gian đĩa của bạn.

So sánh nhật ký với id trong đầu ra trạng thái innodb và bạn sẽ tìm thấy thủ phạm.

+0

Yep ... đó là ý tôi là "SQL log" trong câu hỏi. Việc chọn lọc thông qua nhật ký này không đưa ra bất kỳ tham chiếu nào đến bảng Công việc (cũng như các khóa ngoại trong bảng). Tôi thực sự tò mò tại sao có một thời gian chờ khóa trên một bản cập nhật to.this bảng cho kịch bản này. –

+0

Hmm, nếu chúng thất bại, có thể chúng không bao giờ làm được. Bạn sẽ cần phải tcpdump (đừng quên -s 1500 để có được toàn bộ gói tin khỏi dây). –

+0

Tôi không hoàn toàn chắc chắn ý bạn là gì. Tôi có thể xác nhận rằng câu lệnh UPDATE tới bảng Job làm cho nó thành MySQL, vì nó là dòng cuối cùng trong tệp nhật ký. Điều này được hỗ trợ thêm bằng cách kết xuất đăng nhập ở trên liệt kê UPDATE trong giao dịch 479426. Vấn đề là có một khóa hiện có trên bảng công việc ngăn chặn bản cập nhật. –

4

Nếu truy vấn của bạn đang chờ tối đa ba giây, điều này sẽ giúp bạn dễ dàng chụp trong số slow-query-log. Một gợi ý khác mà Xaprb viết là use InnoTop. Có một số S.O. post on a similar InnoDB lock issue.

Tuy nhiên, bạn có thể muốn xem lại mã và tìm những địa điểm bạn đang chọn toàn bộ bảng. Ví dụ, nếu bạn có một hạng mục công trình bảng và bạn muốn chọn những người đang chờ giải quyết, làm một

SELECT * FROM queue WHERE status = 'pending' ORDER BY create_date LIMIT 1` 

có thể gây ra một tình trạng tạm thời-file-loại mà sẽ chiếm toàn bộ bảng nếu nó nằm trong một Giao dịch. Thêm FOR UPDATE vào lựa chọn có thể giúp nó có được khóa tốt hơn. Rõ ràng, clustering primary keys can help.

Trong môi trường của mình, kết nối truy vấn của tôi sẽ báo cáo lỗi về sự cố khóa giao dịch, vì vậy tôi thấy các lỗi như: Deadlock found when trying to get lock; try restarting transaction.Bạn có thể phải kiểm tra cảnh báo nếu truy vấn của bạn thực sự không thành công. (Điều này có thể không hữu ích nếu bạn không thể thay đổi cách ứng dụng báo cáo lỗi truy vấn.)

+1

Đây là thông tin rất tốt ... cảm ơn bạn! Trong trường hợp cụ thể của tôi, không có truy vấn nào trong giao dịch bên ngoài mất nhiều thời gian (0,1 giây là dài nhất) và - kỳ quặc - không đưa ra bất kỳ tham chiếu nào đến bảng Công việc, nơi hết thời gian chờ khóa. Giải pháp của chúng tôi liên quan đến Hibernate nên không có truy vấn nào đặc biệt phức tạp (tức là không có FOR UPDATEs). Cuối cùng, tôi có lỗi cụ thể: "Đã hết thời gian chờ khóa, hãy thử khởi động lại giao dịch". Tuy nhiên, do lỗi xảy ra trong một giao dịch lồng nhau, không có số lượng giao dịch khởi động lại giúp. –

Các vấn đề liên quan