Sửa lỗi quá thời gian chờ đợi Khóa Khóa vượt quá; Hãy thử khởi động lại giao dịch, vì một bảng Mysql bị "kẹt"?


131

Từ một tập lệnh, tôi đã gửi một truy vấn như thế này hàng ngàn lần đến cơ sở dữ liệu cục bộ của mình:

update some_table set some_column = some_value

Tôi đã quên thêm phần ở đâu, do đó, cùng một cột được đặt thành cùng một giá trị cho tất cả các hàng trong bảng và điều này được thực hiện hàng ngàn lần và cột được lập chỉ mục, vì vậy chỉ mục tương ứng có thể được cập nhật quá nhiều lần .

Tôi nhận thấy có gì đó không ổn, vì mất quá nhiều thời gian, vì vậy tôi đã giết kịch bản. Tôi thậm chí đã khởi động lại máy tính của mình kể từ đó, nhưng một cái gì đó bị kẹt trong bảng, vì các truy vấn đơn giản mất rất nhiều thời gian để chạy và khi tôi thử bỏ chỉ mục có liên quan thì nó thất bại với thông báo này:

Lock wait timeout exceeded; try restarting transaction

Đó là một bảng innodb, vì vậy giao dịch bị kẹt có lẽ là ẩn. Làm cách nào để sửa bảng này và xóa giao dịch bị kẹt khỏi bảng?


3
Đầu ra của là SHOW FULL PROCESSLISTgì?
Wolph

Nó chỉ hiển thị lệnh SHOW FULL PROCESSLIST, không có gì khác. Đó là một cơ sở dữ liệu phát triển địa phương. Không có gì là chạy trên nó. Tôi nhận được thông báo lỗi 'khóa chờ ..' trên dòng lệnh khi tôi cố gắng thả chỉ mục từ đó.
Tom

Trong trường hợp đó, có lẽ bạn đang tạo 2 kết nối riêng biệt trong các giao dịch khác nhau phải chờ nhau.
Wolph

Tôi đã không tạo ra bất kỳ giao dịch nào sau đó. Tôi giết tập lệnh, khởi động lại máy và đăng nhập từ dòng lệnh để nhìn xung quanh. Không có gì khác sử dụng cơ sở dữ liệu ngoại trừ máy khách dòng lệnh mysql, do đó, một cái gì đó phải bị mắc kẹt trong bảng.
Tom

Câu trả lời:


143

Tôi đã có một vấn đề tương tự và giải quyết nó bằng cách kiểm tra các chủ đề đang chạy. Để xem các luồng đang chạy, sử dụng lệnh sau trong giao diện dòng lệnh mysql:

SHOW PROCESSLIST;

Nó cũng có thể được gửi từ phpMyAdmin nếu bạn không có quyền truy cập vào giao diện dòng lệnh mysql.
Điều này sẽ hiển thị một danh sách các chủ đề với id tương ứng và thời gian thực hiện, vì vậy bạn có thể GIẾT các chủ đề đang mất quá nhiều thời gian để thực hiện. Trong phpMyAdmin, bạn sẽ có một nút để dừng các luồng bằng cách sử dụng KILL, nếu bạn đang sử dụng giao diện dòng lệnh, chỉ cần sử dụng lệnh KILL theo sau là id luồng, như trong ví dụ sau:

KILL 115;

Điều này sẽ chấm dứt kết nối cho các chủ đề tương ứng.


36
HÃY LƯU Ý! Điều này đã được ai đó đề cập đến trên 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 chủ đề được mở trong cơ sở dữ liệu trong câu hỏi, ngủ hay không. Đ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 đã đề cập đến một cái gì đó như "Đôi khi một luồng MySQL khóa một bảng, sau đó ngủ trong khi nó chờ đợi một cái gì đó không liên quan đến MySQL xảy ra."
Eric L.

(Tôi đã thêm câu trả lời của riêng mình cho xác thịt mà suy nghĩ ở đây , vào một câu hỏi liên quan)
Eric L.

Điều này đã giúp tôi. Tôi đã có một vài luồng ngủ được tạo bởi tính năng truy vấn / quản lý cơ sở dữ liệu PHPStorm.
Ejaz

Tuyệt quá! Tôi đã có một quá trình ẩn từ 5 giờ mà tôi có thể xác định và giết chết.
Aldo Paradiso

2
đây không phải là một giải pháp nhiều hơn việc băng vào vết thương bị nhiễm trùng là một giải pháp. bạn không giải quyết vấn đề gốc bên dưới.
dùng2914191

55

Bạn có thể kiểm tra các giao dịch hiện đang chạy với

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

Giao dịch của bạn phải là một trong những giao dịch đầu tiên, vì đó là giao dịch cũ nhất trong danh sách. Bây giờ chỉ cần lấy giá trị từ trx_mysql_thread_idvà gửi KILLlệnh:

KILL 1234;

Nếu bạn không chắc chắn giao dịch nào là của bạn, hãy lặp lại truy vấn đầu tiên rất thường xuyên và xem giao dịch nào vẫn tồn tại.


Bạn có thể cần sử dụng tài khoản root để chạy SQL đó để xem giao dịch nào thực sự đang chặn người khác truy cập vào bảng
tom10271

40

Kiểm tra trạng thái InnoDB để tìm khóa

SHOW ENGINE InnoDB STATUS;

Kiểm tra bảng mở MySQL

SHOW OPEN TABLES WHERE In_use > 0;

Kiểm tra các giao dịch InnoDB đang chờ xử lý

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

Kiểm tra phụ thuộc khóa - những gì chặn những gì

SELECT * FROM `information_schema`.`innodb_locks`;

Sau khi điều tra các kết quả ở trên, bạn sẽ có thể thấy những gì đang khóa những gì.

Nguyên nhân cốt lõi của vấn đề cũng có thể nằm trong mã của bạn - vui lòng kiểm tra các chức năng liên quan đặc biệt là các chú thích nếu bạn sử dụng JPA như Hibernate.

Ví dụ, như được mô tả ở đây , việc sử dụng sai các chú thích sau đây có thể gây ra các khóa trong cơ sở dữ liệu:

@Transactional(propagation = Propagation.REQUIRES_NEW) 

4
Cảm ơn bạn rất nhiều! Chạy SELECT * FROM information_schema.innodb_trx t JOIN information_schema.processlist p ON t.trx_mysql_thread_id = p.idđã tiết lộ thủ phạm: Chuỗi khóa xuất phát từ địa chỉ IP của tôi ... Tôi đã quên đóng một bảng điều khiển gỡ lỗi mà tôi đã để lại giữa một giao dịch ...
Elias Strehle

40

Điều này bắt đầu xảy ra với tôi khi kích thước cơ sở dữ liệu của tôi tăng lên và tôi đã thực hiện rất nhiều giao dịch trên đó.

Sự thật có lẽ có một số cách để tối ưu hóa các truy vấn hoặc DB của bạn nhưng hãy thử 2 truy vấn này để khắc phục.

Chạy cái này:

SET GLOBAL innodb_lock_wait_timeout = 5000; 

Và sau đó:

SET innodb_lock_wait_timeout = 5000; 

2
Liên kết tham khảo: innodb_lock_wait_timeout
kết hợp vào

1
Tôi đang chạy một cơ sở dữ liệu 11GB rất bận rộn. Đây là điều duy nhất đã làm việc cho tôi, cảm ơn bạn!
dongemus

Chỉ cần nhớ thay đổi các giá trị thành giá trị trước đó nếu bạn không muốn giữ chúng ở đó mãi mãi.
Ricardo Martins

Điều này có nghĩa là một số người dùng của tôi sẽ có trải nghiệm chậm hơn phải không?
Arnold Roa

9

Khi bạn thiết lập kết nối cho giao dịch, bạn có được khóa trước khi thực hiện giao dịch. Nếu không thể có được khóa, đôi khi bạn thử. Nếu khóa vẫn không thể lấy được, thì thời gian chờ khóa vượt quá lỗi được ném. Tại sao bạn không thể có được khóa là bạn không đóng kết nối. Vì vậy, khi bạn đang cố gắng khóa lần thứ hai, bạn sẽ không thể có được khóa vì kết nối trước đó của bạn vẫn chưa được tiết lộ và giữ khóa.

Giải pháp: đóng kết nối hoặc setAutoCommit(true)(theo thiết kế của bạn) để giải phóng khóa.


7

Khởi động lại MySQL, nó hoạt động tốt.

NHƯNG hãy cẩn thận rằng nếu một truy vấn như vậy bị mắc kẹt, có một vấn đề ở đâu đó:

  • trong truy vấn của bạn (đặt sai vị trí, sản phẩm cartesian, ...)
  • rất nhiều hồ sơ để chỉnh sửa
  • tham gia hoặc kiểm tra phức tạp (MD5, chuỗi con LIKE %...%, v.v.)
  • vấn đề cấu trúc dữ liệu
  • mô hình khóa ngoại (khóa chuỗi / vòng lặp)
  • dữ liệu sai

Như @syedrakib đã nói, nó hoạt động nhưng đây không phải là giải pháp lâu dài cho sản xuất.

Chú ý: thực hiện khởi động lại có thể ảnh hưởng đến dữ liệu của bạn với trạng thái không nhất quán.

Ngoài ra, bạn có thể kiểm tra cách MySQL xử lý truy vấn của bạn bằng từ khóa EXPLAIN và xem liệu có thể có gì đó ở đó để tăng tốc truy vấn không (chỉ mục, kiểm tra phức tạp, ...).


CẢM ƠN BẠN. bạn đã không giải quyết vấn đề của tôi trực tiếp nhưng tôi bị khóa bảng và nó rất tệ. Đó là bài viết duy nhất trên toàn bộ internet, dẫn tôi đến ý tưởng để kiểm tra các khóa ngoại. Vì vậy, tôi phát hiện ra rằng khóa của khóa chính là 11 và khóa ngoại 10. Tôi không biết làm thế nào điều đó có thể xảy ra và tại sao mọi thứ hoạt động trước đó.
EscapeNetscape

@EscapeNetscape bạn đang chào đón, tôi rất vui vì câu trả lời này ít giúp bạn :)
Benj

3

Quá trình Goto trong mysql.

Vì vậy, có thể thấy có nhiệm vụ vẫn làm việc.

Giết quá trình cụ thể hoặc đợi cho đến khi quá trình hoàn thành.


7
Nó giải quyết vấn đề. Nhưng đây không thể là một giải pháp cho máy chủ sản xuất TRỰC TIẾP ...... Làm thế nào chúng ta có thể đưa ra cách xử lý bế tắc này? Hoặc làm thế nào chúng ta có thể TRÁNH Bế tắc này xảy ra?
Rakib

1
tốt, điều đó xảy ra rằng ngay cả với các truy vấn mysql HOÀN HẢO được hình thành tốt và HOÀN TOÀN không được viết bởi nhà phát triển mà bởi giao diện hồ sơ hoạt động của khung, các vấn đề về thời gian chờ khóa vẫn có thể xảy ra. Vì vậy, tôi không viết truy vấn mysql thích hợp là một yếu tố ở đây.
Rakib

1

Tôi gặp vấn đề tương tự với phần "cập nhật". Giải pháp của tôi chỉ đơn giản là chạy qua các hoạt động có sẵn trong phpMyAdmin cho bảng. Tôi đã tối ưu hóa, xóa và phân mảnh bảng (không theo thứ tự đó). Không cần phải bỏ bảng và khôi phục nó từ bản sao lưu cho tôi. :)


1
Nó có thể giải quyết vấn đề. Nhưng việc phải làm điều này mỗi khi xảy ra lỗi như vậy không thể là một giải pháp cho máy chủ sản xuất TRỰC TIẾP ...... Làm thế nào chúng ta có thể đưa ra cách xử lý bế tắc này? Hoặc làm thế nào chúng ta có thể TRÁNH Bế tắc này xảy ra?
Rakib

1

Tôi gặp vấn đề tương tự. Tôi nghĩ đó là một vấn đề bế tắc với SQL. Bạn chỉ có thể buộc đóng quy trình SQL từ Trình quản lý tác vụ. Nếu không khắc phục được, chỉ cần khởi động lại máy tính của bạn. Bạn không cần phải bỏ bảng và tải lại dữ liệu.


Nó giải quyết vấn đề. Nhưng đây không thể là một giải pháp cho máy chủ sản xuất TRỰC TIẾP ...... Làm thế nào chúng ta có thể đưa ra cách xử lý bế tắc này? Hoặc làm thế nào chúng ta có thể TRÁNH Bế tắc này xảy ra?
Rakib

khởi động lại Apache và các dịch vụ của nó (hoặc ít nhất là MySQL), không cần phải khởi động lại
Amjo 7/07/2016

1

Tôi gặp vấn đề này khi cố gắng xóa một nhóm bản ghi nhất định (sử dụng MS Access 2007 với kết nối ODBC với MySQL trên máy chủ web). Thông thường tôi sẽ xóa một số bản ghi khỏi MySQL sau đó thay thế bằng các bản ghi đã cập nhật (tầng xóa một số bản ghi liên quan, điều này hợp lý xóa tất cả các bản ghi liên quan cho một lần xóa bản ghi).

Tôi đã cố gắng chạy qua các hoạt động có sẵn trong phpMyAdmin cho bảng (tối ưu hóa, xóa, v.v.), nhưng tôi đã nhận được sự cho phép cần phải sửa lỗi RELOAD khi tôi cố gắng xóa. Vì cơ sở dữ liệu của tôi nằm trên máy chủ web, tôi không thể khởi động lại cơ sở dữ liệu. Khôi phục từ bản sao lưu không phải là một lựa chọn.

Tôi đã thử chạy truy vấn xóa cho nhóm bản ghi này trên truy cập cPanel mySQL trên web. Có thông báo lỗi tương tự.

Giải pháp của tôi: Tôi đã sử dụng Trình duyệt truy vấn MySQL miễn phí của Sun (Oracle) mà tôi đã cài đặt trước đó trên máy tính của mình) và chạy truy vấn xóa ở đó. Nó làm việc ngay lập tức, Vấn đề được giải quyết. Sau đó tôi đã có thể thực hiện lại chức năng bằng cách sử dụng tập lệnh Access bằng kết nối ODBC Access to MySQL.


-2

Đã sửa nó.

Hãy chắc chắn rằng bạn không có kiểu chèn dữ liệu không khớp trong truy vấn. Tôi gặp vấn đề khi tôi đang thử "dữ liệu tác nhân trình duyệt người dùng" VARCHAR(255)và gặp sự cố với khóa này tuy nhiên khi tôi thay đổi nó thành TEXT(255)nó đã sửa nó.

Vì vậy, rất có thể nó là một sự không phù hợp của loại dữ liệu.


-151

Tôi đã giải quyết vấn đề bằng cách bỏ bảng và khôi phục nó từ bản sao lưu.


20
Ngẫu nhiên, câu trả lời này giành được vinh dự là câu trả lời "Được chấp nhận" được ghi điểm thấp nhất mọi thời đại của SO! 🏆
ashleedawg

1
Đây cũng là câu trả lời được ghi điểm thấp nhất nói chung
Bob Kerman
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.