PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Nhiều chủ đề có thể gây ra các bản cập nhật trùng lặp trên tập hợp bị ràng buộc không?

Các đảm bảo đã nêu của bạn áp dụng trong trường hợp đơn giản này, nhưng không nhất thiết phải áp dụng trong các truy vấn phức tạp hơn một chút. Xem phần cuối của câu trả lời để biết ví dụ.

Trường hợp đơn giản

Giả sử rằng col1 là duy nhất, có chính xác một giá trị "2" hoặc có thứ tự ổn định nên mọi UPDATE khớp với các hàng giống nhau theo cùng một thứ tự:

Điều gì sẽ xảy ra cho truy vấn này là các chủ đề sẽ tìm thấy hàng có col =2 và tất cả đều cố gắng lấy một khóa ghi trên tuple đó. Chính xác là một trong số họ sẽ thành công. Những người khác sẽ chặn chờ giao dịch của chuỗi đầu tiên được cam kết.

Tx đầu tiên đó sẽ ghi, cam kết và trả về số hàng là 1. Cam kết sẽ giải phóng khóa.

Các tx khác sẽ lại cố gắng nắm lấy ổ khóa. Từng người một, họ sẽ thành công. Mỗi giao dịch sẽ lần lượt trải qua quy trình sau:

  • Có được khóa ghi trên bộ dữ liệu đang tranh chấp.
  • Kiểm tra lại WHERE col=2 điều kiện sau khi nhận được khóa.
  • Việc kiểm tra lại sẽ cho thấy rằng điều kiện không còn phù hợp nữa nên UPDATE sẽ bỏ qua hàng đó.
  • UPDATE không có hàng nào khác nên nó sẽ báo cáo không có hàng nào được cập nhật.
  • Cam kết, giải phóng khóa cho lần tiếp theo cố gắng giữ nó.

Trong trường hợp đơn giản này, việc khóa cấp độ hàng và kiểm tra lại điều kiện sẽ tuần tự hóa các bản cập nhật một cách hiệu quả. Trong những trường hợp phức tạp hơn, không quá nhiều.

Bạn có thể dễ dàng chứng minh điều này. Mở nói bốn phiên psql. Trong lần đầu tiên, hãy khóa bảng bằng BEGIN; LOCK TABLE test; . Trong phần còn lại của các phiên, hãy chạy UPDATE giống hệt nhau s - họ sẽ chặn trên khóa cấp bảng. Bây giờ, hãy mở khóa bằng cách COMMIT ting phiên đầu tiên của bạn. Xem chúng chạy đua. Chỉ một sẽ báo cáo số hàng là 1, những người khác sẽ báo cáo 0. Điều này dễ dàng được tự động hóa và theo tập lệnh để lặp lại và mở rộng quy mô lên nhiều kết nối / chuỗi hơn.

Để tìm hiểu thêm, hãy đọc quy tắc viết đồng thời , trang 11 của Các vấn đề về đồng thời PostgreSQL - và sau đó đọc phần còn lại của bản trình bày đó.

Và nếu col1 không phải là duy nhất?

Như Kevin đã lưu ý trong các nhận xét, if col không phải là duy nhất, vì vậy bạn có thể so khớp nhiều hàng, sau đó thực hiện các lần thực thi khác nhau của UPDATE có thể nhận được các thử thách khác nhau. Điều này có thể xảy ra nếu họ chọn các gói khác nhau (giả sử một gói là qua PREPAREEXECUTE và một cái khác là trực tiếp, hoặc bạn đang làm rối với enable_ GUC) hoặc nếu kế hoạch mà tất cả họ sử dụng đều sử dụng một loại giá trị bằng nhau không ổn định. Nếu họ lấy các hàng theo một thứ tự khác thì tx1 sẽ khóa một bộ, tx2 sẽ khóa một bộ khác, sau đó mỗi người sẽ cố gắng lấy khóa trên các bộ đã được khóa của nhau. PostgreSQL sẽ hủy bỏ một trong số chúng với một ngoại lệ deadlock. Đây là một lý do chính đáng khác tại sao tất cả mã cơ sở dữ liệu của bạn nên luôn luôn chuẩn bị để thử lại các giao dịch.

Nếu bạn cẩn thận, hãy đảm bảo UPDATE đồng thời s luôn nhận được các hàng giống nhau theo cùng một thứ tự mà bạn vẫn có thể dựa vào hành vi được mô tả trong phần đầu tiên của câu trả lời.

Thật thất vọng, PostgreSQL không cung cấp UPDATE ... ORDER BY vì vậy việc đảm bảo rằng các bản cập nhật của bạn luôn chọn các hàng giống nhau theo cùng một thứ tự không đơn giản như bạn mong muốn. A SELECT ... FOR UPDATE ... ORDER BY theo sau là UPDATE riêng biệt thường an toàn nhất.

Các truy vấn phức tạp hơn, hệ thống xếp hàng

Nếu bạn đang thực hiện các truy vấn với nhiều giai đoạn, liên quan đến nhiều bộ giá trị hoặc các điều kiện khác với mức bình đẳng, bạn có thể nhận được kết quả đáng ngạc nhiên khác với kết quả của thực hiện nối tiếp. Đặc biệt, chạy đồng thời bất kỳ thứ gì như:

UPDATE test SET col = 1 WHERE col = (SELECT t.col FROM test t ORDER BY t.col LIMIT 1);

hoặc các nỗ lực khác để xây dựng một hệ thống "hàng đợi" đơn giản sẽ * không thành công * để làm việc như bạn mong đợi. Xem tài liệu PostgreSQL về đồng thời bản trình bày này để biết thêm thông tin.

Nếu bạn muốn một hàng đợi công việc được hỗ trợ bởi cơ sở dữ liệu, có các giải pháp đã được thử nghiệm tốt để xử lý tất cả các trường hợp góc phức tạp đáng ngạc nhiên. Một trong những cách phổ biến nhất là PgQ . Có một giấy PgCon hữu ích về chủ đề và tìm kiếm trên Google cho 'hàng đợi postgresql' có đầy đủ các kết quả hữu ích.

BTW, thay vì LOCK TABLE bạn có thể sử dụng SELECT 1 FROM test WHERE col = 2 FOR UPDATE; để có được một khóa ghi chỉ vào đó trên tuple. Điều đó sẽ chặn các cập nhật chống lại nó nhưng không chặn ghi vào các bộ dữ liệu khác hoặc chặn bất kỳ lần đọc nào. Điều đó cho phép bạn mô phỏng các loại vấn đề đồng thời khác nhau.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách thay đổi người dùng thành Superuser trong PostgreSQL

  2. Cách làm việc với cơ sở dữ liệu PostgreSQL

  3. Cách rút ngắn / thêm phút từ dấu thời gian trong postgreSQL

  4. Kiểm soát thời gian chờ khóa PostgreSQL

  5. Sửa đổi giá trị bắt đầu Django AutoField