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

Chức năng dùng mãi mãi để chạy cho số lượng lớn các bản ghi

Hầu hết có thể bạn đang gặp phải điều kiện cuộc đua . Khi bạn chạy chức năng của mình liên tiếp 1000 lần trong các giao dịch riêng biệt , một cái gì đó như thế này sẽ xảy ra:

T1            T2            T3            ...
SELECT max(id) -- id 1
              SELECT max(id)  -- id 1
                            SELECT max(id)  -- id 1
                                          ...
              Row id 1 locked, wait ...
                            Row id 1 locked, wait ...
UPDATE id 1
                                          ... 

COMMIT
              Wake up, UPDATE id 1 again!
              COMMIT
                            Wake up, UPDATE id 1 again!
                            COMMIT
                                          ... 

Được viết lại nhiều hơn và đơn giản hóa dưới dạng hàm SQL:

CREATE OR REPLACE FUNCTION get_result(val1 text, val2 text)
  RETURNS text AS 
$func$
   UPDATE table t
   SET    id_used = 'Y'
        , col1 = val1
        , id_used_date = now() 
   FROM  (
      SELECT id
      FROM   table 
      WHERE  id_used IS NULL
      AND    id_type = val2
      ORDER  BY id
      LIMIT  1
      FOR    UPDATE   -- lock to avoid race condition! see below ...
      ) t1
   WHERE  t.id_type = val2
   -- AND    t.id_used IS NULL -- repeat condition (not if row is locked)
   AND    t.id = t1.id
   RETURNING  id;
$func$  LANGUAGE sql;

Câu hỏi liên quan với nhiều lời giải thích hơn:

Giải thích

  • Không chạy hai câu lệnh SQL riêng biệt. Điều đó tốn kém hơn và mở rộng khung thời gian cho các điều kiện cuộc đua. Một UPDATE với một truy vấn con thì tốt hơn nhiều.

  • Bạn không cần PL / pgSQL cho nhiệm vụ đơn giản. Bạn vẫn có thể sử dụng PL / pgSQL, UPDATE giữ nguyên.

  • Bạn cần phải khóa hàng đã chọn để bảo vệ khỏi các điều kiện của cuộc đua. Nhưng bạn không thể thực hiện việc này với hàm tổng hợp mà bạn đang sử dụng vì theo tài liệu :

  • Tôi nhấn mạnh đậm. May mắn thay, bạn có thể thay thế min(id) dễ dàng với ORDER BY tương đương / LIMIT 1 Tôi đã cung cấp ở trên. Cũng có thể sử dụng một chỉ mục.

  • Nếu bàn lớn, bạn cần một chỉ mục trên id ít nhất. Giả sử rằng id đã được lập chỉ mục dưới dạng PRIMARY KEY , Điều đó sẽ giúp. Nhưng một phần chỉ mục đa cột bổ sung này có thể sẽ giúp nhiều hơn nữa :

    CREATE INDEX foo_idx ON table (id_type, id)
    WHERE id_used IS NULL;
    

Các giải pháp thay thế

Khóa tư vấn Có thể là cách tiếp cận ưu việt ở đây:

Hoặc bạn có thể muốn khóa nhiều hàng cùng một lúc :




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. JPA SequenceGenerator và GeneratedValue:thuộc tính tên / máy tạo chỉ duy nhất cho mỗi lớp?

  2. Vectơ địa lý ST_HexagonGrid để tìm tất cả các điểm

  3. Cách hoạt động của Acosh () trong PostgreSQL

  4. PostgreSQL tìm kết hợp phổ biến của các cặp trên cùng một cột

  5. Nhận bảng và cột sở hữu một chuỗi