2012-04-20 29 views
19

Tôi là một chút bối rối đọc về deadlocks PostgreSQL.Deadlocks trong PostgreSQL khi chạy UPDATE

Một ví dụ điển hình bế tắc là:

-- Transaction 1 
UPDATE customer SET ... WHERE id = 1 
UPDATE customer SET ... WHERE id = 2 

-- Transaction 2 
UPDATE customer SET ... WHERE id = 2 
UPDATE customer SET ... WHERE id = 1 

Nhưng nếu tôi thay đổi mã như sau:

-- Transaction 1 
UPDATE customer SET ... WHERE id IN (1, 2) 

-- Transaction 2 
UPDATE customer SET ... WHERE id IN (1, 2) 

Sẽ là một khả năng bế tắc ở đây?

Về cơ bản câu hỏi của tôi là: trong trường hợp thứ hai PostgreSQL khóa từng hàng một hay khóa toàn bộ phạm vi được bao phủ bởi điều kiện WHERE?

Cảm ơn trước!

Trả lời

28

Trong PostgreSQL các hàng sẽ bị khóa khi chúng được cập nhật - trên thực tế, cách thức thực sự hoạt động là mỗi tuple (phiên bản của hàng) có một trường hệ thống được gọi là xmin để chỉ ra giao dịch nào đã thực hiện gói hiện tại (bằng cách chèn hoặc cập nhật) và trường hệ thống được gọi là xmax để cho biết giao dịch nào đã hết hạn mà tuple (bằng cách cập nhật hoặc xóa). Khi bạn truy cập dữ liệu, nó sẽ kiểm tra mỗi bộ dữ liệu để xác định xem nó có hiển thị với giao dịch của bạn không, bằng cách kiểm tra "ảnh chụp nhanh" đang hoạt động của bạn dựa vào các giá trị này.

Nếu bạn đang thực hiện CẬP NHẬT và một tuple phù hợp với điều kiện tìm kiếm của bạn có xmin sẽ hiển thị cho ảnh chụp nhanh của bạn và xmax của giao dịch đang hoạt động, nó chặn, chờ giao dịch đó hoàn tất. Nếu giao dịch mà lần đầu tiên cập nhật tuple quay trở lại, giao dịch của bạn sẽ thức dậy và xử lý hàng; nếu giao dịch đầu tiên cam kết, giao dịch của bạn sẽ thức dậy và thực hiện hành động tùy thuộc vào mức cô lập giao dịch hiện tại.

Rõ ràng, bế tắc là kết quả của việc này xảy ra với các hàng theo thứ tự khác nhau. Không có khóa cấp độ hàng trong RAM có thể thu được cho tất cả các hàng cùng một lúc, nhưng nếu các hàng được cập nhật theo cùng thứ tự bạn không thể có khóa tròn. Thật không may, cú pháp IN(1, 2) được đề xuất không đảm bảo điều đó. Các phiên khác nhau có thể có các yếu tố chi phí khác nhau hoạt động, tác vụ "phân tích" nền có thể thay đổi thống kê cho bảng giữa việc tạo kế hoạch và kế hoạch khác hoặc có thể sử dụng seqscan và bị ảnh hưởng bởi tối ưu hóa PostgreSQL. để tham gia một trong những tiến trình và "vòng quanh" để giảm đĩa I/O.

Nếu bạn thực hiện cập nhật từng lần theo cùng một thứ tự, trong mã ứng dụng hoặc sử dụng con trỏ, khi đó bạn sẽ chỉ chặn đơn giản, không phải khóa chết. Nói chung, mặc dù, các cơ sở dữ liệu quan hệ dễ bị lỗi tuần tự hóa và tốt nhất là truy cập chúng thông qua một khung công tác sẽ nhận ra chúng dựa trên SQLSTATE và tự động thử lại toàn bộ giao dịch ngay từ đầu. Trong PostgreSQL, lỗi tuần tự hóa sẽ luôn có SQLSTATE là 40001 hoặc 40P01.

http://www.postgresql.org/docs/current/interactive/mvcc-intro.html

+0

Cảm ơn! Vì vậy, ví dụ trên của tôi có thể gây ra bế tắc (vì chúng tôi không biết thứ tự, trong đó các hàng được xử lý trong cả hai giao dịch)? – vyakhir

+0

Nó có thể gây ra bế tắc, mặc dù điều đó hiếm khi xảy ra; trái với ví dụ đầu tiên (lựa chọn rõ ràng các đơn đặt hàng khác nhau), nơi nó sẽ là phổ biến. Bạn có thể loại trừ deadlocks bằng cách lấy một khóa mức độ thích hợp ở mức bảng trong suốt thời gian của mỗi giao dịch cập nhật bảng, nhưng việc chữa trị đó có thể tệ hơn bệnh. Xem phần tài liệu tôi đã tham khảo để biết chi tiết. – kgrittn

+0

Nhưng PostgreSQL có phát hành khóa sau khi hàng đã được cập nhật hay không, nhưng toàn bộ câu lệnh UPDATE vẫn chưa kết thúc? Nói cách khác, nếu chúng tôi có tuyên bố như CẬP NHẬT ... WHERE id IN (1,2,3,4,5) sau khi cập nhật postgresql, nói, hàng có id = 1 và tiếp tục với hàng có id = 2, nó sẽ phát hành hàng id = 1? nếu có, làm thế nào nó sẽ cuộn các hàng trở lại nếu cần thiết? – vyakhir

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