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

Các chuỗi không có khoảng trống PostgreSQL

Các chuỗi có khoảng trống để cho phép chèn đồng thời. Cố gắng tránh các khoảng trống hoặc sử dụng lại các ID đã xóa sẽ tạo ra các vấn đề về hiệu suất khủng khiếp. Xem Câu hỏi thường gặp về PostgreSQL wiki.

PostgreSQL SEQUENCE s được sử dụng để cấp phát ID. Chúng chỉ ngày càng tăng và chúng được miễn các quy tắc khôi phục giao dịch thông thường để cho phép nhiều giao dịch lấy ID mới cùng một lúc. Điều này có nghĩa là nếu một giao dịch quay trở lại, những ID đó sẽ bị "vứt bỏ"; không có danh sách các ID "miễn phí" được lưu giữ, chỉ có bộ đếm ID hiện tại. Các chuỗi cũng thường được tăng lên nếu cơ sở dữ liệu tắt không sạch.

Khóa tổng hợp (ID) vô nghĩa dù sao. Thứ tự của chúng không đáng kể, tính chất quan trọng duy nhất của chúng là tính độc nhất. Bạn không thể đo lường một cách có ý nghĩa độ "xa nhau" của hai ID, cũng như không thể nói một cách có ý nghĩa nếu một ID lớn hơn hay nhỏ hơn một ID khác. Tất cả những gì bạn có thể làm là nói "bằng" hoặc "không bằng". Bất cứ điều gì khác là không an toàn. Bạn không nên quan tâm đến khoảng trống.

Nếu bạn cần một chuỗi không có khoảng trống sử dụng lại các ID đã bị xóa, bạn có thể có một chuỗi, bạn chỉ cần từ bỏ một lượng lớn hiệu suất cho nó - đặc biệt, bạn không thể có bất kỳ đồng thời nào trên INSERT s tất cả, bởi vì bạn phải quét bảng để tìm ID miễn phí thấp nhất, khóa bảng để ghi để không giao dịch nào khác có thể yêu cầu cùng một ID. Thử tìm kiếm "chuỗi không có khoảng trống postgresql".

Cách tiếp cận đơn giản nhất là sử dụng bảng bộ đếm và một hàm lấy ID tiếp theo. Đây là phiên bản tổng quát sử dụng bảng bộ đếm để tạo các ID không có khoảng trống liên tiếp; Tuy nhiên, nó không sử dụng lại các ID.

CREATE TABLE thetable_id_counter ( last_id integer not null );
INSERT INTO thetable_id_counter VALUES (0);

CREATE OR REPLACE FUNCTION get_next_id(countertable regclass, countercolumn text) RETURNS integer AS $$
DECLARE
    next_value integer;
BEGIN
    EXECUTE format('UPDATE %s SET %I = %I + 1 RETURNING %I', countertable, countercolumn, countercolumn, countercolumn) INTO next_value;
    RETURN next_value;
END;
$$ LANGUAGE plpgsql;

COMMENT ON get_next_id(countername regclass) IS 'Increment and return value from integer column $2 in table $1';

Cách sử dụng:

INSERT INTO dummy(id, blah) 
VALUES ( get_next_id('thetable_id_counter','last_id'), 42 );

Lưu ý rằng khi một giao dịch đang mở đã nhận được ID, tất cả các giao dịch khác sẽ cố gắng gọi get_next_id sẽ chặn cho đến khi giao dịch đầu tiên cam kết hoặc quay trở lại. Điều này là không thể tránh khỏi và đối với các ID không có lỗ hổng và do thiết kế.

Nếu bạn muốn lưu trữ nhiều bộ đếm cho các mục đích khác nhau trong một bảng, chỉ cần thêm một tham số vào hàm trên, thêm một cột vào bảng bộ đếm và thêm một WHERE mệnh đề UPDATE khớp với tham số với cột đã thêm. Bằng cách đó, bạn có thể có nhiều hàng bộ đếm được khóa độc lập. Đ ừng chỉ cần thêm các cột bổ sung cho bộ đếm mới.

Chức năng này không sử dụng lại các ID đã xóa, nó chỉ tránh tạo ra các khoảng trống.

Để sử dụng lại ID, tôi khuyên ... không nên sử dụng lại ID.

Nếu bạn thực sự phải làm như vậy, bạn có thể làm như vậy bằng cách thêm ON INSERT OR UPDATE OR DELETE kích hoạt trên bảng quan tâm để thêm các ID đã xóa vào bảng bên danh sách miễn phí và xóa chúng khỏi bảng danh sách miễn phí khi chúng INSERT ed. Xử lý một UPDATE dưới dạng DELETE theo sau là INSERT . Bây giờ, hãy sửa đổi hàm tạo ID ở trên để nó thực hiện SELECT free_id INTO next_value FROM free_ids FOR UPDATE LIMIT 1 và nếu tìm thấy, DELETE s hàng đó. IF NOT FOUND nhận ID mới từ bảng trình tạo như bình thường. Đây là phần mở rộng chưa được thử nghiệm của chức năng trước đó để hỗ trợ tái sử dụng:

CREATE OR REPLACE FUNCTION get_next_id_reuse(countertable regclass, countercolumn text, freelisttable regclass, freelistcolumn text) RETURNS integer AS $$
DECLARE
    next_value integer;
BEGIN
    EXECUTE format('SELECT %I FROM %s FOR UPDATE LIMIT 1', freelistcolumn, freelisttable) INTO next_value;
    IF next_value IS NOT NULL THEN
        EXECUTE format('DELETE FROM %s WHERE %I = %L', freelisttable, freelistcolumn, next_value);
    ELSE
        EXECUTE format('UPDATE %s SET %I = %I + 1 RETURNING %I', countertable, countercolumn, countercolumn, countercolumn) INTO next_value;
    END IF;
    RETURN next_value;
END;
$$ LANGUAGE plpgsql;



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Thêm ngày vào một ngày trong PostgreSQL

  2. Cách liệt kê Cơ sở dữ liệu và Bảng trong PostgreSQL

  3. Nhận giá trị chung nhất cho mỗi giá trị của cột khác trong SQL

  4. Tên các quy trình PostgreSQL trong Windows

  5. Thay thế động cho trục xoay với CASE và GROUP BY