설명서 를 이해할 수 있듯이 다음 정의는 동일합니다.
create table foo (
id serial primary key,
code integer,
label text,
constraint foo_uq unique (code, label));
create table foo (
id serial primary key,
code integer,
label text);
create unique index foo_idx on foo using btree (code, label);
그러나 Postgres 9.4 매뉴얼 에 다음 과 같은 메모가 있습니다 .
테이블에 고유 제한 조건을 추가하는 선호되는 방법은
ALTER TABLE ... ADD CONSTRAINT
입니다. 고유 제한 조건을 시행하기 위해 인덱스를 사용하는 것은 직접 액세스해서는 안되는 구현 세부 사항으로 간주 될 수 있습니다.
(편집 :이 메모는 Postgres 9.5 설명서에서 제거되었습니다.)
좋은 스타일의 문제입니까? 이러한 변형 중 하나 (예 : 성능)를 선택하면 실질적인 결과는 무엇입니까?
답변
나는이 기본이지만 중요한 문제에 대해 약간의 의문이 있었으므로 모범으로 배우기로 결정했습니다.
의 테스트 테이블 만들어 보자 마스터 두 개의 열, con_id 고유 제한 조건으로하고 ind_id 고유 인덱스에 의해 색인.
create table master (
con_id integer unique,
ind_id integer
);
create unique index master_unique_idx on master (ind_id);
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_unique_idx" UNIQUE, btree (ind_id)
테이블 설명 (psql의 \ d)에서 고유 인덱스의 고유 제약 조건을 알 수 있습니다.
독창성
만약을 대비하여 독창성을 확인합시다.
test=# insert into master values (0, 0);
INSERT 0 1
test=# insert into master values (0, 1);
ERROR: duplicate key value violates unique constraint "master_con_id_key"
DETAIL: Key (con_id)=(0) already exists.
test=# insert into master values (1, 0);
ERROR: duplicate key value violates unique constraint "master_unique_idx"
DETAIL: Key (ind_id)=(0) already exists.
test=#
예상대로 작동합니다!
외래 키
이제 master 의 두 열을 참조하는 두 개의 외래 키로 세부 테이블을 정의 합니다 .
create table detail (
con_id integer,
ind_id integer,
constraint detail_fk1 foreign key (con_id) references master(con_id),
constraint detail_fk2 foreign key (ind_id) references master(ind_id)
);
Table "public.detail"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Foreign-key constraints:
"detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
"detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
글쎄, 오류가 없습니다. 작동하는지 확인하십시오.
test=# insert into detail values (0, 0);
INSERT 0 1
test=# insert into detail values (1, 0);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk1"
DETAIL: Key (con_id)=(1) is not present in table "master".
test=# insert into detail values (0, 1);
ERROR: insert or update on table "detail" violates foreign key constraint "detail_fk2"
DETAIL: Key (ind_id)=(1) is not present in table "master".
test=#
외래 키에서 두 열을 모두 참조 할 수 있습니다.
인덱스를 이용한 제약
기존 고유 인덱스를 사용하여 테이블 제약 조건을 추가 할 수 있습니다.
alter table master add constraint master_ind_id_key unique using index master_unique_idx;
Table "public.master"
Column | Type | Modifiers
--------+---------+-----------
con_id | integer |
ind_id | integer |
Indexes:
"master_con_id_key" UNIQUE CONSTRAINT, btree (con_id)
"master_ind_id_key" UNIQUE CONSTRAINT, btree (ind_id)
Referenced by:
TABLE "detail" CONSTRAINT "detail_fk1" FOREIGN KEY (con_id) REFERENCES master(con_id)
TABLE "detail" CONSTRAINT "detail_fk2" FOREIGN KEY (ind_id) REFERENCES master(ind_id)
이제 열 제약 조건 설명에는 차이가 없습니다.
부분 인덱스
테이블 제약 조건 선언에서는 부분 인덱스를 만들 수 없습니다. 그것은에서 직접 제공 정의 의 create table ...
. 고유 인덱스 선언에서 WHERE clause
부분 인덱스를 생성하도록 설정할 수 있습니다. 또한 표현식 (열뿐만 아니라)에 대한 색인 을 작성 하고 다른 매개 변수 (데이터 정렬, 정렬 순서, NULL 배치)를 정의 할 수도 있습니다 .
당신은 할 수없는 부분 인덱스를 사용하여 테이블에 제약 조건을 추가 할 수 있습니다.
alter table master add column part_id integer;
create unique index master_partial_idx on master (part_id) where part_id is not null;
alter table master add constraint master_part_id_key unique using index master_partial_idx;
ERROR: "master_partial_idx" is a partial index
LINE 1: alter table master add constraint master_part_id_key unique ...
^
DETAIL: Cannot create a primary key or unique constraint using such an index.
답변
UNIQUE INDEX
vs 를 사용하는 또 다른 이점은 UNIQUE CONSTRAINT
쉽게 DROP
/ CREATE
인덱스 CONCURRENTLY
할 수 있지만 제약 조건으로는 할 수 없다는 것입니다.
답변
독창성은 제약입니다. 인덱스는 주어진 값이 이미 존재하는지 판별하기 위해 인덱스가 기존의 모든 값을 신속하게 검색 할 수 있기 때문에 고유 인덱스를 작성하여 구현됩니다.
개념적으로 인덱스는 구현 세부 사항이며 고유성은 제약 조건과 만 관련되어야합니다.
따라서 속도 성능은 동일해야합니다
답변
내가 만난 또 다른 것은 제약 조건이 아닌 고유 인덱스에서 SQL 표현식을 사용할 수 있다는 것입니다.
따라서 이것은 작동하지 않습니다.
CREATE TABLE users (
name text,
UNIQUE (lower(name))
);
그러나 다음 작품.
CREATE TABLE users (
name text
);
CREATE UNIQUE INDEX uq_name on users (lower(name));
답변
다양한 사람들이 고유 제약 조건보다 고유 인덱스의 이점을 제공했기 때문에 여기에는 단점이 있습니다. 고유 제약 조건은 연기 될 수 있고 (트랜잭션 끝에서만 확인 가능) 고유 인덱스는 불가능합니다.
답변
나는 문서에서 이것을 읽었다.
table_constraint 추가 [유효하지 않음]
이 형식은와 동일한 구문과
CREATE TABLE
옵션을 사용하여 테이블에 새 제약 조건을 추가합니다. 이 옵션NOT VALID
은 현재 외래 키 제약 조건에만 허용됩니다. 제한 조건이 표시NOT VALID
되면 테이블의 모든 행이 제한 조건을 만족하는지 검증하기위한 잠재적으로 긴 초기 점검이 생략 됩니다. 후속 삽입 또는 업데이트 에 대해 제한 조건이 계속 적용 됩니다 (즉, 참조 된 테이블에 일치하는 행이 없으면 실패합니다). 그러나 데이터베이스 는 VALIDATE CONSTRAINT 옵션을 사용하여 유효성이 검증 될 때까지 테이블의 모든 행에 대해 제한 조건이 있다고 가정 하지 않습니다 .
제약 조건을 추가하여 이것이 “부분 고유성”이라고 생각합니다.
그리고 독창성을 보장하는 방법에 대해 :
고유 제약 조건을 추가하면 제약 조건에 나열된 열 또는 열 그룹에 고유 B- 트리 인덱스가 자동으로 생성됩니다. 일부 행만 포함하는 고유성 제한은 고유 제한 조건으로 작성할 수 없지만 고유 부분 인덱스를 작성하여 이러한 제한을 적용 할 수 있습니다.
참고 : 테이블에 고유 제한 조건을 추가하는 선호되는 방법은 ALTER TABLE… ADD CONSTRAINT입니다. 고유 제한 조건을 시행하기 위해 인덱스를 사용하는 것은 직접 액세스해서는 안되는 구현 세부 사항으로 간주 될 수 있습니다. 그러나 고유 한 열에 인덱스를 수동으로 만들 필요가 없다는 것을 알아야합니다. 그렇게하면 자동으로 생성 된 인덱스가 복제됩니다.
따라서 고유성을 보장하기 위해 인덱스를 작성하는 제한 조건을 추가해야합니다.
이 문제를 어떻게 알 수 있습니까?
“제약”은 문법적 으로이 칼럼이 고유해야한다는 것을 목표로 하며 , 법과 규칙을 확립합니다. “인덱스”는 “구현 방법, 고유성을 달성하는 방법, 구현에있어 고유 한 의미”에 대해 의미 론적 입니다. 따라서 Postgresql이 구현하는 방식은 매우 논리적입니다. 먼저 열이 고유해야한다고 선언 한 다음 Postgresql은 고유 인덱스 추가 구현을 추가합니다 .
답변
잠금에는 차이가 있습니다.
인덱스를 추가해도 테이블에 대한 읽기 액세스는 차단되지 않습니다.
제약 조건을 추가하면 ALTER TABLE을 통해 추가되므로 테이블 잠금이 적용되므로 모든 선택이 차단 됩니다.