MySql Gap Lock Bế tắc khi chèn


8

Tôi nhận được Deadlocks từ các khóa khoảng cách trên bàn khi thường xuyên chèn vào nó từ nhiều nguồn. Dưới đây là tổng quan về các quy trình của tôi.

START TRANSACTION
  UPDATE vehicle_image
  SET active = 0
  WHERE vehicleID = SOMEID AND active = 1

  Loop:
    INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath, vehicleImageSplashFilePath
      ,vehicleImageThumbnailFilePath, vehicleImageMiniFilePath, mainVehicleImage, active)
    VALUES (%s, %s, %s, %s, %s, %s, 1);
END TRANSACTION

Đầu ra của SHOW Create table vehicle_image;là:

CREATE TABLE `vehicle_image` (
  `vehicleImageID` int(11) NOT NULL AUTO_INCREMENT,
  `vehicleID` int(11) DEFAULT NULL,
  `vehicleImageFilePath` varchar(200) DEFAULT NULL,
  `vehicleImageSplashFilePath` varchar(200) DEFAULT NULL,
  `vehicleImageThumbnailFilePath` varchar(200) DEFAULT NULL,
  `vehicleImageMiniFilePath` varchar(200) DEFAULT NULL,
  `mainVehicleImage` bit(1) DEFAULT NULL,
  `active` bit(1) DEFAULT b'1',
  `userCreated` int(11) DEFAULT NULL,
  `dateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `userModified` int(11) DEFAULT NULL,
  `dateModified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`vehicleImageID`),
  KEY `active` (`active`),
  KEY `mainvehicleimage` (`mainVehicleImage`),
  KEY `vehicleid` (`vehicleID`)
) ENGINE=InnoDB AUTO_INCREMENT=22878102 DEFAULT CHARSET=latin1

Và bế tắc cuối cùng được đưa ra bởi SHOW engine innodb status:

LATEST DETECTED DEADLOCK
------------------------
2018-03-27 12:31:15 11a58
*** (1) TRANSACTION:
TRANSACTION 5897678083, ACTIVE 2 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 873570, OS thread handle 0x124bc, query id 198983754 ec2-34-239-240-179.compute-1.amazonaws.com 34.239.240.179 image_processor update
INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath, vehicleImageSplashFilePath, vehicleImageThumbnailFilePath, vehicleImageMiniFilePath, mainVehicleImage, active)
VALUES (70006176, 'f180928(1)1522168276.230837full.jpg', 'f180928(1)1522168276.230837splash.jpg', 'f180928(1)1522168276.230837thumb.jpg', 'f180928(1)1522168276.230837mini.jpg', 1, 1)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 875 page no 238326 n bits 472
  index `vehicleid` of table `ipacket`.`vehicle_image` trx id 5897678083
  lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 378 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 842c365a; asc  ,6Z;;
 1: len 4; hex 815d03bc; asc  ]  ;;

*** (2) TRANSACTION:
TRANSACTION 5897678270, ACTIVE 1 sec inserting, thread declared inside InnoDB 5000
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 873571, OS thread handle 0x11a58, query id 198983849 ec2-35-171-169-21.compute-1.amazonaws.com 35.171.169.21 image_processor update
INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath, vehicleImageSplashFilePath, vehicleImageThumbnailFilePath, vehicleImageMiniFilePath, mainVehicleImage, active)
VALUES (70006326, '29709(1)1522168277.4443843full.jpg', '29709(1)1522168277.4443843splash.jpg', '29709(1)1522168277.4443843thumb.jpg', '29709(1)1522168277.4443843mini.jpg', 1, 1)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 875 page no 238326 n bits 464
  index `vehicleid` of table `ipacket`.`vehicle_image` trx id 5897678270
  lock_mode X locks gap before rec
Record lock, heap no 378 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 842c365a; asc  ,6Z;;
 1: len 4; hex 815d03bc; asc  ]  ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 875 page no 238326 n bits 472
  index `vehicleid` of table `ipacket`.`vehicle_image` trx id 5897678270
  lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 378 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 4; hex 842c365a; asc  ,6Z;;
 1: len 4; hex 815d03bc; asc  ]  ;;

*** WE ROLL BACK TRANSACTION (2)

Tôi đang chạy nhiều quy trình này cùng một lúc nhưng không bao giờ chạy hai quy trình đang sử dụng như nhau VehicleID. Tôi thực sự bối rối về lý do tại sao tôi nhận được Deadlocks.

Tôi đã tạm thời giải quyết vấn đề bằng cách sử dụng cấp độ Cách ly READ COMMITTED, nhưng tôi đã đọc được rằng điều này đòi hỏi phải thay đổi để nhân rộng trong đó bạn phải thực hiện sao chép cấp hàng.

Tôi đã đọc các câu hỏi khác ở đây tương tự như của tôi, nhưng tôi hơi mới đối với SQL và vẫn không thể hiểu tại sao điều này xảy ra.

Câu hỏi tương tự:
- Bế tắc về thống kê chèn MySQL
- Bế tắc của MySQL InnoDB cho 2 truy vấn chèn đơn giản

CẬP NHẬT:

Tôi phát hiện ra rằng việc sử dụng READ COMMITTEDchưa thực sự giải quyết được vấn đề. Tôi vẫn chưa tìm ra lý do tại sao các bế tắc đang xảy ra và tôi thực sự không biết làm thế nào để chẩn đoán thêm bất cứ điều gì hiện tại tôi có. Tôi đang tiếp tục nhận Deadlocks trong hệ thống sản xuất của mình. Bất kỳ trợ giúp sẽ được đánh giá cao.


Bạn có thể vui lòng cho chúng tôi biết thêm chi tiết - cụ thể: Cấu hình đĩa, số lượng đĩa, đặc điểm hiệu suất? RAM, bao nhiêu? CPU, số lượng và hiệu suất? Số lượng giao dịch mỗi giây, mỗi phút, mỗi giờ và mỗi ngày? Những tỷ lệ này thay đổi theo thời gian? Chính xác thì những bế tắc này ảnh hưởng đến hiệu suất như thế nào? Hãy cho chúng tôi đầu ra của SHOW PROCESSLIST;. Hầu hết thời gian, REPEATABLE READlà mức cô lập tốt nhất cho hầu hết các ứng dụng, vì vậy tôi sẽ không quá quan tâm đến việc sử dụng nó. Có sự gia tăng hiệu suất đáng chú ý khi bạn thay đổi nó từ mặc định - REPEATABLE READ?
Vérace

Làm thế nào mà có thể làm việc? Bạn có chuỗi không trích dẫn đi vào VARCHARs.
Rick James

CUỘC ĐỜI KẾT THÚC ở đâu?
Rick James

@RickJames Tôi không có chuỗi không trích dẫn đi vào VARCHARS, các truy vấn hoạt động như mong đợi khi chạy 95% thời gian. END LOOP được biểu thị bằng cách quay trở lại cùng cấp. Ví dụ: Vòng lặp bắt đầu, tôi chạy câu lệnh chèn đó nhiều lần, sau đó vòng lặp kết thúc và giao dịch kết thúc. Lưu ý rằng đó loopchỉ là mã giả để thể hiện những gì đang diễn ra.
Brian Sizemore

@ Vérace Lặp lại Đọc là mặc định cho bảng này (sử dụng công cụ innodb). Tôi thực sự thử nghiệm thay đổi nó từ repeatable readđể read committedmà là một mức độ cách ly thấp sau đó đọc lặp lại, nhưng tiếc là nó không dừng lại bế tắc. Tôi biết rằng phần cứng sẽ ảnh hưởng đến máy chủ (ví dụ ec2, tôi sẽ phải tìm thông tin cụ thể) nhưng tôi không nghĩ rằng thông tin đó sẽ là cần thiết để hiểu lý do tại sao các bế tắc xảy ra. Bản chất lẻ tẻ của điều này cũng làm cho khó nắm bắt đầu ra của danh sách quy trình hiển thị; khi bế tắc xảy ra.
Brian Sizemore

Câu trả lời:


4

Tôi không phải là chuyên gia về MySQL, nhưng nhìn vào nhật ký Deadlock của bạn, mặc dù bạn đang CHỌN ID xe khác nhau cho mỗi câu lệnh, những yêu cầu này phải khóa toàn bộ dữ liệu (238326) của VehicleIDchỉ mục không được nhóm .

Thực tế là bạn thỉnh thoảng gặp bế tắc có nghĩa là trong vòng 1 trang bạn có nhiều ID xe, do đó, có khả năng nhỏ là 2 quy trình khác nhau sẽ cần khóa cho cùng một trang.

Điều tốt nhất để khuyên là giữ cho các giao dịch của bạn càng nhỏ càng tốt .

Nếu có một số cách bạn có thể làm như sau, nó sẽ giúp giảm bớt nguy cơ bế tắc:

START TRANSACTION;
  UPDATE vehicle_image SET active = 0 WHERE vehicleID = SOMEID and active = 1;
END TRANSACTION;
Loop:
  START TRANSACTION;
  INSERT INTO vehicle_image (vehicleID, vehicleImageFilePath,
    vehicleImageSplashFilePath, vehicleImageThumbnailFilePath,
    vehicleImageMiniFilePath, mainVehicleImage, active)
  VALUES (%s, %s, %s, %s, %s, %s, 1);  
  END TRANSACTION;
--EndLoop here

Nếu bạn có thể, hãy thử thay đổi hệ số lấp đầy của chỉ số đó thành 95% và kiểm tra xem bạn có nhận được ít bế tắc hơn không.

Một thử nghiệm cực đoan hơn sẽ là loại bỏ hoàn toàn chỉ mục đó trong khi CHỌN, sau đó tạo lại nó khi hoàn tất.


Bạn có hiểu biết sâu sắc về lý do tại sao toàn bộ trang sẽ bị khóa Vs chỉ các hàng mà tôi đang cố gắng chèn không?
Brian Sizemore

1
Ngoài ra, tôi sẽ cấu trúc lại mã của mình một chút và giảm thời gian giao dịch. Tôi tin rằng bạn đúng rằng nó sẽ tạo ra một sự khác biệt đáng kể.
Brian Sizemore

Không chắc chắn làm thế nào các phần bên trong của MySQL hoạt động, nhưng câu trả lời này giải thích nó cho MS SQL. Một số mẹo MySQL tốt trong Hướng dẫn sử dụng MySQL cũng vậy.
Oreo

1
MySQL không cung cấp quyền kiểm soát đối với fillfactor.
Rick James

2
Sau khi cấu trúc lại mã của tôi để Xếp hàng các phần chèn của tôi và câu lệnh cập nhật và chạy chúng rất gần nhau, nó đã giải quyết vấn đề của tôi. Không chỉ vậy, nhưng tôi đã có thể tiếp tục nhân rộng điều này (gần gấp đôi số lượng quy trình song song trước đó) và nó vẫn hoạt động chính xác. Cảm ơn bạn Oreo!
Brian Sizemore

1

MySQL không chỉ khóa hàng bị ảnh hưởng mà cả hàng chỉ mục bị ảnh hưởng và khoảng cách giữa các hàng chỉ mục (như được mô tả ở đây ). Vì các khóa chính luôn được lập chỉ mục và bạn sử dụng chúng trong các bản cập nhật của mình, tôi nghi ngờ rằng nhiều giao dịch cố gắng cập nhật nhiều hàng mỗi kết quả trong các khóa khoảng cách chỉ mục chồng chéo sẽ tạo ra bế tắc.

Để giải quyết điều này, tôi cũng khuyên bạn nên tư vấn Oreos để giữ một giao dịch nhỏ nhất có thể. Nếu các hàng được cập nhật độc lập với nhau, bạn nên sử dụng giao dịch riêng cho từng giao dịch.

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.