Đây là một chút rắc rối trong việc triển khai IF NOT EXISTS
cho bảng và lược đồ. Về cơ bản, chúng là một nỗ lực cao cấp và PostgreSQL không xử lý các điều kiện cuộc đua một cách rõ ràng. Nó an toàn, nhưng xấu xí.
Nếu lược đồ đang được tạo đồng thời trong một phiên khác nhưng chưa được cam kết, thì nó vừa tồn tại vừa không tồn tại, tùy thuộc vào bạn là ai và giao diện của bạn. Các giao dịch khác không thể "nhìn thấy" lược đồ mới trong danh mục hệ thống bởi vì nó không được cam kết, vì vậy nó được nhập trong pg_namespace
không hiển thị với các giao dịch khác. Vì vậy, CREATE SCHEMA
/ CREATE TABLE
cố gắng tạo ra nó vì đối tượng đó không tồn tại.
Tuy nhiên, điều đó sẽ chèn một hàng vào một bảng với một ràng buộc duy nhất. Các ràng buộc duy nhất phải có thể nhìn thấy các hàng không được cam kết để hoạt động. Vì vậy, các khối chèn (dừng) cho đến khi giao dịch đầu tiên thực hiện CREATE
cam kết hoặc quay trở lại. Nếu nó cam kết, giao dịch thứ hai sẽ hủy bỏ, vì nó đã cố gắng chèn một hàng vi phạm một ràng buộc duy nhất. CREATE SCHEMA
không đủ thông minh để nắm bắt trường hợp này và thử lại.
Để khắc phục đúng cách PostgreSQL này có thể sẽ cần khóa vị từ, nơi nó có thể khóa tiềm năng cho một hàng . Điều này có thể được thêm vào như một phần của công việc hiện tại đang diễn ra để triển khai UPSERT
.
Đối với các lệnh cụ thể này, PostgreSQL có thể thực hiện đọc bẩn của danh mục hệ thống, nơi nó có thể thấy những thay đổi chưa được cam kết. Sau đó, nó có thể đợi giao dịch không được cam kết thực hiện hoặc quay trở lại, thực hiện lại quá trình đọc bẩn để xem liệu người khác có đang đợi hay không và thử lại. Nhưng điều này sẽ có một điều kiện chạy đua trong đó người khác có thể tạo lược đồ giữa khi bạn thực hiện việc đọc để kiểm tra nó và khi bạn cố gắng tạo nó.
Vì vậy, IF NOT EXISTS
các biến thể sẽ phải:
- Kiểm tra xem lược đồ có tồn tại hay không; nếu có, hãy kết thúc mà không cần làm gì cả.
- Cố gắng tạo bảng
- Nếu quá trình tạo không thành công do một lỗi ràng buộc duy nhất, hãy thử lại khi bắt đầu
- Nếu tạo bảng thành công, hãy hoàn thành
Theo như tôi biết không ai thực hiện điều đó, hoặc họ đã thử và nó không được chấp nhận. Sẽ có những vấn đề có thể xảy ra với tỷ lệ ghi ID giao dịch, v.v., với cách tiếp cận này.
Tôi nghĩ đây là một loại lỗi, nhưng đó là loại lỗi "vâng, chúng tôi biết", không phải loại lỗi "chúng tôi sẽ sửa chữa ngay". Hãy đăng lên pgsql-bug về nó; ít nhất thì tài liệu cũng nên đề cập đến cảnh báo này về IF NOT EXISTS
.
Tôi không khuyên bạn nên làm DDL đồng thời như vậy.