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

Ràng buộc loại trừ trên một cột chuỗi bit với toán tử AND bit

Khi chỉnh sửa của bạn được làm rõ, bạn đã cài đặt tiện ích mở rộng btree_gist . Nếu không có nó, ví dụ sẽ không thành công tại name WITH = .

CREATE EXTENSION btree_gist;

Các lớp toán tử được cài đặt bởi btree_gist bao gồm nhiều nhà khai thác. Thật không may, & nhà điều hành không nằm trong số đó. Rõ ràng là vì nó không trả về boolean điều mà một nhà điều hành dự kiến ​​sẽ đủ điều kiện.

Giải pháp thay thế

Tôi sẽ sử dụng kết hợp b-cây chỉ mục nhiều cột (cho tốc độ) và một trình kích hoạt thay vì. Hãy xem xét bản trình diễn này, được thử nghiệm trên PostgreSQL 9.1 :

CREATE TABLE t (
  name text 
 ,value bit(8)
);

INSERT INTO t VALUES ('a', B'10101010'); 

CREATE INDEX t_name_value_idx ON t (name, value);

CREATE OR REPLACE FUNCTION trg_t_name_value_inversion_prohibited()
  RETURNS trigger AS
$func$
BEGIN
IF EXISTS (
     SELECT 1 FROM t
     WHERE (name, value) = (NEW.name, ~ NEW.value)  -- example: exclude inversion
     ) THEN

    RAISE EXCEPTION 'Your text here!';
END IF;

RETURN NEW;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER insup_bef_t_name_value_inversion_prohibited
BEFORE INSERT OR UPDATE OF name, value  -- only involved columns relevant!
ON t
FOR EACH ROW
EXECUTE PROCEDURE trg_t_name_value_inversion_prohibited();

INSERT INTO t VALUES ('a', ~ B'10101010');  -- fails with your error msg.

Sẽ hoạt động rất tốt, thực sự tốt hơn so với ràng buộc loại trừ, bởi vì việc duy trì chỉ mục b-tree rẻ hơn chỉ mục GiST. Và tra cứu với = cơ bản toán tử sẽ nhanh hơn tra cứu giả định với & nhà điều hành.

Giải pháp này không an toàn như một ràng buộc loại trừ, vì trình kích hoạt có thể dễ dàng bị phá vỡ hơn - ví dụ:trong lần kích hoạt tiếp theo trên cùng một sự kiện hoặc nếu trình kích hoạt bị tắt tạm thời. Hãy chuẩn bị để kiểm tra thêm trên toàn bộ bảng nếu các điều kiện đó được áp dụng.

Điều kiện phức tạp hơn

Trình kích hoạt mẫu chỉ bắt được sự đảo ngược của giá trị . Như bạn đã làm rõ trong nhận xét của mình, bạn thực sự cần một điều kiện như sau:

IF EXISTS (
      SELECT 1 FROM t
      WHERE  name = NEW.name
      AND    value & NEW.value <> B'00000000'::bit(8)
      ) THEN

Điều kiện này đắt hơn một chút, nhưng vẫn có thể sử dụng một chỉ mục. Chỉ mục nhiều cột từ phía trên sẽ hoạt động - nếu bạn vẫn cần nó. Hoặc, hiệu quả hơn một chút, một chỉ mục đơn giản trên tên:

CREATE INDEX t_name_idx ON t (name);

Như bạn đã nhận xét, chỉ có thể có tối đa 8 hàng riêng biệt cho mỗi name , ít hơn trong thực tế. Vì vậy, điều này vẫn sẽ nhanh chóng.

Hiệu suất INSERT cao nhất

Nếu INSERT hiệu suất là điều tối quan trọng, đặc biệt nếu nhiều lần cố gắng CHÈN không đạt được điều kiện, bạn có thể làm thêm:tạo chế độ xem cụ thể hóa giá trị được tổng hợp trước per name :

CREATE TABLE mv_t AS 
SELECT name, bit_or(value) AS value
FROM   t
GROUP  BY 1
ORDER  BY 1;

tên được đảm bảo là duy nhất ở đây. Tôi muốn sử dụng CHÌA KHÓA CHÍNH trên name để cung cấp chỉ mục mà chúng tôi đang theo dõi:

ALTER TABLE mv_t SET (fillfactor=90);

ALTER TABLE mv_t
ADD CONSTRAINT mv_t_pkey PRIMARY KEY(name) WITH (fillfactor=90);

Sau đó, INSERT của bạn có thể trông như thế này:

WITH i(n,v) AS (SELECT 'a'::text, B'10101010'::bit(8)) 
INSERT INTO t (name, value)
SELECT n, v
FROM   i
LEFT   JOIN mv_t m ON m.name = i.n
                  AND m.value & i.v <> B'00000000'::bit(8)
WHERE  m.n IS NULL;          -- alternative syntax for EXISTS (...)

fillfactor chỉ hữu ích nếu bảng của bạn nhận được nhiều cập nhật.

Cập nhật các hàng trong dạng xem cụ thể hóa trong TRIGGER SAU KHI CHÈN HOẶC CẬP NHẬT tên, giá trị HOẶC XÓA để giữ cho nó hiện tại. Chi phí của các đối tượng bổ sung phải được cân nhắc với lợi ích. Phần lớn phụ thuộc vào tải thông thường của bạn.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để PyPy, Django và PostgreSQL hoạt động cùng nhau?

  2. Sử dụng pg_notify trong hàm kích hoạt PostgreSQL

  3. TypeORM FindOperator với máy biến áp

  4. Cách current_time hoạt động trong PostgreSQL

  5. Chuyển đổi thủ tục lưu trữ SQL Server thành thủ tục lưu trữ PostgreSQL