2012-04-09 12 views
8

Tôi đang đối mặt với một sự cố bế tắc từ một hàm PL/pgSQL trong cơ sở dữ liệu PostgreSQL của tôi. Vui lòng tìm câu lệnh SQL trong khối mã (chỉ cần ví dụ):Lỗi bế tắc được phát hiện trong hàm PL/pgSQL

BEGIN 
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%'; 
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A'; 
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM; 
END; 

Tôi đã tìm thấy bế tắc xảy ra trong khi phát biểu này đang chạy. Nhưng tôi không chắc rằng có những phát biểu khác đang cố gắng cập nhật bảng này trong cùng một thời điểm (vì tôi không tìm thấy bất kỳ điều gì trong hệ thống đăng nhập của tôi).

Vì vậy, có thể xảy ra bế tắc trong tuyên bố này không? Theo tôi biết, nếu chúng tôi chặn toàn bộ tuyên bố với BEGIN/END. Sẽ có cùng một giao dịch và không nên tự khóa.

+0

Bạn có bất kỳ trình kích hoạt nào trên tài khoản không? Ngoài ra bạn có sử dụng khóa rõ ràng không? – strkol

+1

Theo mặc định, giao dịch có thể quan sát các thay đổi do các giao dịch khác thực hiện. Để biết thêm thông tin, xem [Cách ly giao dịch] (http://www.postgresql.org/docs/current/static/transaction-iso.html) từ tài liệu PostgreSQL. –

+0

@strkol Có, nhưng tuyên bố trong trình kích hoạt đó không liên quan đến bảng này. Đối với khóa rõ ràng cũng có. –

Trả lời

11

Chắc chắn có một số quy trình khác cạnh tranh cho cùng một tài nguyên. Đó là bản chất của bế tắc. Một chức năng như bạn hiển thị không bao giờ có thể bế tắc chính nó. Xem comment by @kgrittn below, một chuyên gia về đồng thời trong PostgreSQL là ai.

Phiên bản PostgreSQL của bạn bị thiếu. Các phiên bản hiện đại nâng cao thông báo lỗi chi tiết . Cả hai quy trình cạnh tranh cho tài nguyên được liệt kê chi tiết với cài đặt ghi nhật ký chuẩn. Kiểm tra nhật ký db của bạn.

Thực tế là bạn bắt lỗi có thể ngăn Postgres cung cấp cho bạn đầy đủ chi tiết. Xóa số EXCEPTION chặn từ hàm plpgsql của bạn, nếu bạn không nhận được thông tin trong nhật ký db và thử lại.

Để giảm bớt sự bế tắc, bạn có thể thực hiện một số việc. Nếu tất cả các khách hàng của bạn truy cập tài nguyên theo thứ tự được đồng bộ, thì các khóa chết không thể xảy ra. Hướng dẫn cung cấp chiến lược cơ bản để giải quyết hầu hết các trường hợp trong chương về deadlocks.


Đối với phiên bản 8.3: xem xét nâng cấp lên phiên bản mới hơn. Đặc biệt cải thiện này trong phiên bản 8.4 nên rất thú vị cho bạn (quoting the release notes):

Khi báo cáo một bế tắc, báo cáo nội dung của tất cả các truy vấn liên quan đến bế tắc vào nhật ký máy chủ (Itagaki Takahiro)

Ngoài ra, phiên bản 8.3 sẽ đáp ứng end of life in February 2013 của nó. Bạn nên bắt đầu xem xét nâng cấp.

Tình huống bế tắc liên quan đến VACUUM phải là fixed in 8.3.1.

+0

Tôi có postgres 8.3.6. Tuyên bố này chỉ sử dụng ví dụ. Trên thực tế, tôi sử dụng bản ghi chèn vào bảng khác thay vì THÔNG BÁO RAISE. –

+0

Thông thường, thông báo lỗi sẽ cung cấp cho bạn thông tin bạn cần. Tôi thêm một chút vào câu trả lời của mình. –

+0

Cảm ơn rất nhiều vì lời khuyên của bạn. Tôi sẽ tiếp tục tìm thấy những gì các quá trình khác đang cố gắng làm điều gì đó với bảng này. –

-1

Trong PostgreSQL, bắt đầu có nghĩa là bạn bắt đầu giao dịch lô.

Bản cập nhật đầu tiên của bạn sẽ khóa các hàng cho các tài khoản WHERE acct_name like 'A%'; Những hàng này được khóa độc quyền sau lần cập nhật đầu tiên.

Cập nhật thứ hai cố gắng mở chính xác các hàng giống như lần cập nhật đầu tiên, để cập nhật không thành công, vì bản cập nhật đầu tiên chưa được cam kết.

Do đó, cập nhật lần truy cập thứ hai là bế tắc.

+0

Trong PL/pgSQL 'BEGIN' chỉ là khởi đầu của một khối mã. Không giống như 'BEGIN' /' COMMIT' trong SQL thuần túy. –

0

Bạn sẽ không gặp vấn đề bế tắc, nếu bạn thêm cam kết, để giải phóng khóa độc quyền.

BEGIN 
UPDATE accounts SET balance = 0 WHERE acct_name like 'A%'; 
COMMIT; 
UPDATE accounts SET balance = balance + 100 WHERE acct_name like '%A'; 
EXCEPTION WHEN OTHERS THEN RAISE NOTICE SQLERRM; 
END; 
+1

Thủ tục trong plpgsql chạy trong khối cam kết giao dịch đơn lẻ, Vì vậy, không có cam kết trong các thủ tục. – sharafjaffri