postgres에서 지연 가능한 고유 인덱스


14

alter table에 대한 postgres 문서를 살펴보면 일반적인 제약 조건이 DEFERRABLE(더 구체적으로, INITIALLY DEFERRED내가 관심있는 것) 으로 표시 될 수있는 것 같습니다 .

다음과 같은 경우 인덱스를 제약 조건과 연결할 수도 있습니다.

색인은 표현식 열을 포함하거나 부분 색인을 가질 수 없습니다

현재 다음과 같은 조건을 가진 고유 색인을 가질 수있는 방법이 없다고 생각합니다.

CREATE UNIQUE INDEX unique_booking
  ON public.booking
  USING btree
  (check_in, check_out)
  WHERE booking_status = 1;

일하기 INITIALLY DEFERRED(경우 고유성 '제약'에만 트랜잭션의 끝 부분에 대한 확인됩니다, 의미, SET CONSTRAINTS ALL DEFERRED;사용된다).

내 가정은 정확합니까? 그렇다면 의도 한 행동을 달성 할 수있는 방법이 있습니까?

감사

답변:


15

인덱스는 지연 될 수 없습니다. 인덱스가 제한적 UNIQUE이든 아니든 상관 없습니다 UNIQUE. 제약 조건의 다른 유형 ( FOREIGN KEY, PRIMARY KEY, EXCLUDE하지만 -)도, 연기 있습니다 CHECK제약.

따라서 트랜잭션의 끝이 아닌 모든 명령문에서 (그리고 현재 구현의 모든 행 삽입 / 업데이트 후에) 고유 부분 인덱스 (및 구현하는 암시 적 제한 조건)가 검사됩니다.


이 제약 조건을 지연 가능하게 구현하려는 경우 디자인에 테이블을 하나 더 추가하는 것이 가능합니다. 이 같은:

CREATE TABLE public.booking_status
  ( booking_id int NOT NULL,               -- same types
    check_in timestamp NOT NULL,           -- as in  
    check_out timestamp NOT NULL,          -- booking
    CONSTRAINT unique_booking
        UNIQUE (check_in, check_out)
        DEFERRABLE INITIALLY DEFERRED,
    CONSTRAINT unique_booking_fk
        FOREIGN KEY (booking_id, check_in, check_out)
        REFERENCES public.booking (booking_id, check_in, check_out)
        DEFERRABLE INITIALLY DEFERRED
  ) ;

이 디자인을 사용하고 booking_status가능한 두 가지 옵션 (0과 1) 만 있다고 가정하면 완전히 제거 할 수 있습니다 booking(에 행이 booking_status있으면 0이 아닌 경우 1입니다).


다른 방법은 EXCLUDE제약 조건을 사용하는 것입니다 .

ALTER TABLE booking
    ADD CONSTRAINT unique_booking
        EXCLUDE 
          ( check_in  WITH =, 
            check_out WITH =, 
            (CASE WHEN booking_status = 1 THEN TRUE END) WITH =
          ) 
        DEFERRABLE INITIALLY DEFERRED ;

dbfiddle 에서 테스트되었습니다 .

위의 기능 :

  • CASE표현 될 NULLbooking_status우리가 쓸 수 null 또는 1보다 다른 (CASE WHEN booking_status = 1 THEN TRUE END)같은 (booking_status = 1 OR NULL)것을 더 이상 명확를 만드는 경우가.

  • 고유 제한 조건과 제외 제한 조건은 하나 이상의 표현식이 NULL 인 행을 승인합니다. 따라서로 필터링 된 인덱스 역할을합니다 WHERE booking_status = 1.

  • 모든 WITH연산자는 제약 조건으로 =작동 UNIQUE합니다.

  • 이 두 조합은 제약 조건이 필터링 된 고유 인덱스로 작동하도록합니다.

  • 그러나 그것은 제약이며 EXCLUDE제약은 연기 될 수 있습니다.


2
EXCLUDE 버전의 경우 +1이 필요했습니다. EXCLUDE의 기능을 보여주는 또 다른 예는 다음과 같습니다. cybertec-postgresql.com/en/postgresql-exclude-beyond-unique
Benjamin Peter

(CASE WHEN booking_status = 1 THEN TRUE END) WITH =)) WHERE (booking_status = 1)"제외 제약 조건이 색인을 사용하여 구현 됨" 으로 대체되어야 하며이 부분 색인 WHERE이 더 작고 빠릅니다 ( postgresql.org/docs/current/sql-createtable.htmlpostgresql.org/docs/current/sql- createindex.html
Denis Ryzhkov

1

이 질문의 몇 년이 지났지 만 스페인 사람들을 위해 분명히하고 싶습니다. 테스트는 Postgres에서 수행되었습니다.

키트가 기본 키인 1337 레코드 테이블에 다음 제한 조건이 추가되었습니다.

**Bloque 1**
ALTER TABLE ele_kitscompletos
ADD CONSTRAINT unique_div_nkit
PRIMARY KEY (div_nkit) 

그러면 테이블에 대해 기본 기본 키 NOT DEFERRED가 생성되므로 다음 UPDATE를 시도하면 오류가 발생합니다.

update ele_kitscompletos
set div_nkit = div_nkit + 1; 

오류 : 중복 키가 고유성 제한을 위반 함«unique_div_nkit»

Postgres에서 각 ROW에 대해 UPDATE를 실행하면 RESTRICTION 또는 CONSTRAINT가 충족되는지 확인합니다.


CONSTRAINT IMMEDIATE가 작성되고 각 명령문이 개별적으로 실행됩니다.

ALTER TABLE ele_kitscompletos
ADD CONSTRAINT unique_div_nkit
PRIMARY KEY (div_nkit)
DEFERRABLE INITIALLY IMMEDIATE

**Bloque 2**
BEGIN;   
UPDATE ele_kitscompletos set div_nkit = div_nkit + 1;
INSERT INTO public.ele_kitscompletos(div_nkit, otro_campo)
VALUES 
  (1338, '888150502');
COMMIT;

쿼리 OK, 영향을받는 0 개의 행 (실행 시간 : 0ms; 총 시간 : 0ms) 쿼리 OK, 영향을받는 1328 개의 행 (실행 시간 : 858ms; 총 시간 : 858ms) 오류 : llave duplicada viola restricción de unicidad«unique_div_nkit»DETAIL : La la lave (div_nkit) = (1338).

여기서 SI는 1 차 키 전체를 실행하므로 기본 키를 변경할 수 있습니다 (1328 행). 그러나 트랜잭션 (BEGIN)에 있지만 CONSTRAINT는 COMMIT를 작성하지 않고 각 문장을 완료하자마자 유효성이 검증되므로 INSERT를 실행할 때 오류가 발생합니다. 마지막으로 CONSTRAINT DEFERRED를 작성하여 다음을 수행하십시오.

**Bloque 3**
ALTER TABLE public.ele_edivipol
DROP CONSTRAINT unique_div_nkit RESTRICT;   

ALTER TABLE ele_edivipol
ADD CONSTRAINT unique_div_nkit
PRIMARY KEY (div_nkit)
DEFERRABLE INITIALLY DEFERRED

** Block 2 **의 각 문장을 개별적으로 실행하면 각 문장을 개별적으로 실행하면 INSERT는 유효성을 검사하지 않기 때문에 오류가 발생하지 않지만 불일치를 발견하면 최종 COMMIT가 실행됩니다.


영어로 된 자세한 정보는 다음 링크를 확인하십시오.

깊이의 지연 가능한 SQL 제약

정의 할 수 없음과 초기에 즉시 정의 할 수 없음

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.