Sau khi thực hiện thêm một số bài đọc, tôi nhận thấy rằng, vì InnoDB sử dụng khóa cấp độ hàng, các bế tắc có thể xảy ra khi chỉ chèn hoặc cập nhật một hàng duy nhất vì các hành động không phải là nguyên tử. Tôi đã chạy:
SHOW ENGINE INNODB STATUS
để tìm thông tin về lần bế tắc cuối cùng. Tôi đã tìm thấy:
------------------------
LATEST DETECTED DEADLOCK
------------------------
140106 17:22:41
*** (1) TRANSACTION:
TRANSACTION 63EB5222A, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 9 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 2
MySQL thread id 4304350, OS thread handle 0x7fd3b74d3700, query id 173460207 192.168.0.2 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '27739' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1389046866'
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB5222A lock_mode X waiting
*** (2) TRANSACTION:
TRANSACTION 63EB52225, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
177 lock struct(s), heap size 31160, 17786 row lock(s), undo log entries 2
MySQL thread id 4304349, OS thread handle 0x7fd6961c8700, query id 173460194 192.168.0.1 sharecash Updating
UPDATE `click_rollups` SET `clicks` = `clicks` + 1, `last_updated` = '1389046961' WHERE `camp_id` = '30949' AND `country` = 'US' AND `clicks` < '1000' AND `time_created` = '1388964767'
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 186 page no 407 n bits 1272 index `country` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 186 page no 512 n bits 384 index `PRIMARY` of table `sharecash`.`click_rollups` trx id 63EB52225 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (1)
Bạn có thể thấy rằng hai truy vấn đang gây ra bế tắc thực sự là những truy vấn chính xác giống nhau. Nó cho thấy rằng cũng có các tham số khác nhau cho các cột trong mệnh đề WHERE, vì vậy các hàng thực tế đang bị khóa là khác nhau, điều này có vẻ hơi phản trực quan đối với tôi - làm thế nào các hoạt động trên các tập hợp hàng khác nhau có thể gây ra bế tắc?
Câu trả lời dường như là sự bế tắc đang phát sinh từ các mục nhập khóa công cụ truy vấn trong cấu trúc lập chỉ mục. Nếu bạn nhìn vào kết quả ở trên, bạn có thể thấy rằng một giao dịch có khóa trên một phần nhất định của một trang nhất định ở country
lập chỉ mục và cần khóa một phần của chỉ mục khóa chính, trong khi giao dịch khác về cơ bản là trường hợp ngược lại.
Một điều bất biến trong phần này của ứng dụng của chúng tôi là chỉ một hàng sẽ có ít hơn 1000 lần nhấp, vì vậy tôi tin rằng bằng cách khắc phục vấn đề đó, vấn đề bế tắc sẽ được giảm thiểu, vì tổng thể sẽ ít khóa hơn. Tài liệu MySQL đề xuất mã hóa các ứng dụng của bạn để luôn cấp lại các giao dịch trong trường hợp khôi phục do bế tắc, điều này sẽ ngăn vấn đề này gây ra lỗi cho các trang. Tuy nhiên, nếu bất kỳ ai có bất kỳ ý tưởng nào khác về cách thực sự tránh được những bế tắc này, một lần nữa, vui lòng đăng chúng trong phần bình luận!
CHỈNH SỬA -
country
giao dịch không cần sử dụng chỉ mục, đối với mỗi camp_id
giá trị chỉ có một số ít (thường chỉ 1) giá trị khác nhau của country
, mỗi trong số đó chỉ tương ứng với một hàng. Tôi đã thêm gợi ý chỉ mục vào truy vấn để làm cho nó ngừng sử dụng chỉ mục này và sự cố hiện đã được khắc phục mà không có bất kỳ tác động nào về hiệu suất (có thể là một mức tăng nhỏ).