Từ Cách ly Giao dịch trang:
EXPLAIN
trên SELECT
đó có thể cho bạn biết kế hoạch truy vấn đang được thực hiện là gì, nhưng nếu bảng nhỏ (hoặc trống!), PostgreSQL gần như chắc chắn sẽ chọn một lần quét tuần tự thay vì tham chiếu chỉ mục. Điều này sẽ gây ra khóa vị từ trên toàn bộ bảng, gây ra lỗi tuần tự hóa bất cứ khi nào giao dịch khác thực hiện bất kỳ điều gì với bảng.
Trên hệ thống của tôi:
isolation=# EXPLAIN SELECT * from mydevice where cid = 1;
QUERY PLAN
----------------------------------------------------------
Seq Scan on mydevice (cost=0.00..23.38 rows=5 width=46)
Filter: (cid = 1)
(2 rows)
Bạn có thể thử thêm một chỉ mục và buộc nó sử dụng:
isolation=# CREATE INDEX mydevice_cid_key ON mydevice (cid);
CREATE INDEX
isolation=# SET enable_seqscan = off;
SET
isolation=# EXPLAIN SELECT * from mydevice where cid = 1;
QUERY PLAN
----------------------------------------------------------------------------------
Index Scan using mydevice_cid_key on mydevice (cost=0.00..8.27 rows=1 width=46)
Index Cond: (cid = 1)
(2 rows)
Tuy nhiên, đây không phải là giải pháp chính xác. Hãy sao lưu một chút.
Serializable có nghĩa là để đảm bảo rằng các giao dịch sẽ có cùng hiệu ứng như thể chúng được chạy lần lượt, mặc dù thực tế là bạn đang thực sự chạy các giao dịch này đồng thời. PostgreSQL không có tài nguyên vô hạn, vì vậy, mặc dù đúng là nó đặt các khóa vị từ trên dữ liệu mà truy vấn của bạn thực sự truy cập, "dữ liệu" có thể có nghĩa nhiều hơn "hàng được trả về".
PostgreSQL chọn gắn cờ các lỗi tuần tự hóa khi cho rằng có thể có vấn đề, chứ không phải khi chắc chắn. (Do đó, cách nó tổng quát hóa khóa hàng thành khóa trang.) Lựa chọn thiết kế này gây ra kết quả dương tính giả, chẳng hạn như lỗi trong ví dụ của bạn. Tuy nhiên, kết quả dương tính giả ít hơn mức lý tưởng, nó không ảnh hưởng đến tính đúng đắn của ngữ nghĩa cô lập.
Thông báo lỗi là:
ERROR: could not serialize access due to read/write dependencies among transactions
DETAIL: Reason code: Canceled on identification as a pivot, during commit attempt.
HINT: The transaction might succeed if retried.
Gợi ý đó là chìa khóa. Ứng dụng của bạn cần phải xử lý các lỗi tuần tự hóa và thử lại toàn bộ hoạt động . Điều này đúng bất cứ khi nào SERIALIZABLE
đang chơi - nó đảm bảo tính chính xác nối tiếp mặc dù đồng thời, nhưng nó không thể làm được điều đó nếu không có sự trợ giúp của ứng dụng của bạn. Nói cách khác, nếu bạn thực sự đang thực hiện các sửa đổi đồng thời, cách duy nhất PostgreSQL có thể đáp ứng các yêu cầu cách ly là yêu cầu ứng dụng của bạn tự tuần tự hóa. Như vậy: