CHỌN … ĐỂ CẬP NHẬT có tác dụng phụ [không quá] đáng ngạc nhiên đối với các hàng không tồn tại. nó có thể gây ra một hình phạt hiệu suất [nghiêm trọng] và thậm chí ngăn cản bạn chèn hàng mới
Khóa hàng để cập nhật
Nhóm phát triển của chúng tôi đang làm việc trên một ứng dụng cần đảm bảo cập nhật trên một mục hàng không bị sửa đổi bởi một giao dịch khác. Đương nhiên, họ bắt đầu sử dụng CHỌN … ĐỂ CẬP NHẬT để khóa hàng trước khi cập nhật nó. Điều này hoạt động tuyệt vời để ngăn bất kỳ ai khác cập nhật hàng này. Tuy nhiên, họ bắt đầu nhận được một số thời gian chờ khóa trên các phần chèn mới của các mục hoàn toàn không liên quan trong quá trình kiểm tra tải và họ đã yêu cầu tôi xem xét vấn đề này
SELECT … FOR UPDATE được mô tả như sau trong tài liệu MySQL.
______0
Cho đến giờ vẫn ổn. hành vi này dự kiến sẽ xảy ra. Nó cũng không đề cập đến bất cứ điều gì về việc khóa bất cứ thứ gì ngoại trừ các hàng mà nó đọc.
Tôi đã hỏi nhóm liệu họ có đang cố gắng chèn cùng một dữ liệu khi họ đang khóa trong giao dịch khác hay không và họ nói rằng họ không cố gắng.
Trong mã giả, họ đã làm điều này.
______1
Cột uuid ở đây là khóa chính của bảng. Mã này thực thi tốt và không có vấn đề gì khi chỉ là một giao dịch.
Bạn có thể thắc mắc tại sao không sử dụng lệnh INSERT … ON DUPLICATE KEY UPDATE hoặc REPLACE INTO?
Trước hết, chúng tôi chỉ thỉnh thoảng mới chèn, vì vậy 99% lệnh chèn sẽ không thực hiện được . Thứ hai, chúng tôi chỉ có thể cập nhật một cột trong một hàng, do đó, điều đó có nghĩa là chúng tôi cần biết toàn bộ hàng trước khi chúng tôi phải chèn hoặc thay thế hàng.
Không có hàng để cập nhật
Bây giờ điều gì sẽ xảy ra nếu không có hàng nào để cập nhật?
Theo mô tả trong tài liệu MySQL, nó đặt một khóa độc quyền trên mỗi hàng mà nó đọc, nhưng khi không có hàng nào để đọc thì sao? .
______2
Nếu không có hàng, khóa sẽ vẫn được đặt trên các mục nhập chỉ mục được liên kết. Điều này không nên xấu, phải không? . nó không phải là một khóa khoảng cách một mình, mà là một.
Vì khóa được đặt trên mục nhập chỉ mục không tồn tại nên khóa phím tiếp theo được tạo. Tùy thuộc vào nơi bạn sẽ chèn vào chỉ mục, bạn có thể thấy toàn bộ phạm vi bị khóa vì nó cần chèn trong phạm vi này. Trong phiên bản UUID của chúng tôi, điều này không xảy ra thường xuyên vì có một yếu tố ngẫu nhiên, nhưng nó vẫn có thể xảy ra thường xuyên nếu bạn chỉ có một vài hàng trong bảng của mình. Trong trường hợp đó, khoảng cách giữa các UUID lớn và do yếu tố ngẫu nhiên, yu cuối cùng có thể khóa các khoảng trống lớn trong chỉ mục. Vì độ trễ giữa các khu vực xuất hiện trên hệ thống này, điều này giúp khóa phím tiếp theo mở lâu hơn và khả năng xảy ra va chạm trong khoảng cách cũng tăng lên một chút. Vì vậy, điều đó giải thích hành vi trong quá trình kiểm tra tải. Vì vậy, tất cả đều tốt, kết thúc tốt đẹp?
Tác dụng phụ khó chịu của khóa Next-Key
Có một tác dụng phụ khó chịu với khóa phím tiếp theo. nếu giá trị chỉ mục sẽ lớn hơn giá trị lớn nhất trong bảng, nó sẽ khóa mọi thứ trên giá trị lớn nhất cho đến vô cùng
Vậy điều gì sẽ xảy ra với một bảng trong đó khóa chính là thứ tự giống như một số nguyên? .
______3
Điều này sẽ tạo ra khoảng cách từ 5 đến 10 và khoảng cách từ 15 đến vô cùng.
Khi chúng tôi đang chọn trong khoảng trống giữa 5 và 10, chúng tôi tạo khóa phím tiếp theo trong khoảng từ 5 đến 10 và chúng tôi không thể chèn các hàng mới vào trong khoảng trống này. Tuy nhiên, chúng ta vẫn có thể chèn các hàng mới vào cuối bảng. Tuy nhiên, nếu chúng tôi chọn một hàng trên id lớn hơn 15, chúng tôi sẽ đặt khóa phím tiếp theo từ 15 đến vô cùng. Điều này có nghĩa là không ai có thể thêm bất cứ thứ gì vào bảng này nữa cho đến khi chúng tôi thực hiện giao dịch của mình. Điều này có thể trở thành nút cổ chai nghiêm trọng nếu bạn chèn nhiều hàng hơn cập nhật
Phần kết luận
Tôi không biết rằng CHỌN … ĐỂ CẬP NHẬT thực sự đã khóa chỉ mục cho các hàng chưa tồn tại. Tôi đã lý luận rằng nếu không có hàng nào được chọn thì sẽ không có gì để khóa. Và nếu không có gì để khóa, thì toàn bộ CHỌN … ĐỂ CẬP NHẬT sẽ đơn giản là xì hơi