PostgreSQL 에서 enable,disable,vaidate 외 키 로 구 속 된 인 스 턴 스

나 는 더 이상 쓸데없는 말 을 하지 않 겠 으 니,모두들 직접 실례 를 보 는 것 이 좋 겠 다.

postgres=# create table t1(a int primary key,b text,c date);
CREATE TABLE
postgres=# create table t2(a int primary key,b int references t1(a),c text);
CREATE TABLE
postgres=# insert into t1 (a,b,c) values(1,'aa',now());
INSERT 0 1
postgres=# insert into t1 (a,b,c) values(2,'bb',now());
INSERT 0 1
postgres=# insert into t2 (a,b,c) values (1,1,'aa');
INSERT 0 1
postgres=# insert into t2 (a,b,c) values (2,2,'aa');
INSERT 0 1
postgres=# \d t1
         Table "public.t1"
 Column | Type  | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 a   | integer |      | not null |
 b   | text  |      |     |
 c   | date  |      |     |
Indexes:
  "t1_pkey" PRIMARY KEY, btree (a)
Referenced by:
  TABLE "t2" CONSTRAINT "t2_b_fkey" FOREIGN KEY (b) REFERENCES t1(a)
 
postgres=# \d t2
         Table "public.t2"
 Column | Type  | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 a   | integer |      | not null |
 b   | integer |      |     |
 c   | text  |      |     |
Indexes:
  "t2_pkey" PRIMARY KEY, btree (a)
Foreign-key constraints:
  "t2_b_fkey" FOREIGN KEY (b) REFERENCES t1(a)
 
postgres=#
만약 우리 가 스 크 립 트 를 통 해 표 에 데 이 터 를 불 러 오고 싶다 고 가정 합 니 다.스 크 립 트 에 불 러 오 는 순 서 를 모 르 기 때문에 표 t2 의 외 키 제약 을 사용 하지 않 기로 결 정 했 습 니 다.데이터 불 러 온 후에 외 키 제약 을 불 러 오기 로 결 정 했 습 니 다.

postgres=# alter table t2 disable trigger all;
ALTER TABLE
postgres=#
여기 가 좀 이상해 보일 수도 있 지만,외부 키 의 제약 을 사용 하지 않 는 것 은 사실이다.다른 외 키 제약 이 있다 면 당연히 사용 하지 않 습 니 다.
시계 t2 를 다시 봅 시다.

postgres=# \d t2
         Table "public.t2"
 Column | Type  | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 a   | integer |      | not null |
 b   | integer |      |     |
 c   | text  |      |     |
Indexes:
  "t2_pkey" PRIMARY KEY, btree (a)
Foreign-key constraints:
  "t2_b_fkey" FOREIGN KEY (b) REFERENCES t1(a)
Disabled internal triggers:
  "RI_ConstraintTrigger_c_75213" AFTER INSERT ON t2 FROM t1 NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_check_ins"()
  "RI_ConstraintTrigger_c_75214" AFTER UPDATE ON t2 FROM t1 NOT DEFERRABLE INITIALLY IMMEDIATE FOR EACH ROW EXECUTE PROCEDURE "RI_FKey_check_upd"()
 
postgres=#
키워드 all 은 표 의 다른 내부 트리거 도 사용 하지 않 습 니 다.슈퍼 서가 있어 야 실행 할 수 있 습 니 다.

postgres=# create user abce with login password 'abce';
CREATE ROLE
postgres=# \c postgres abce
You are now connected to database "postgres" as user "abce".
postgres=> create table t3 ( a int primary key, b text, c date);
CREATE TABLE
postgres=> create table t4 ( a int primary key, b int references t3(a), c text);
CREATE TABLE
postgres=> alter table t4 disable trigger all;
ERROR: permission denied: "RI_ConstraintTrigger_c_75235" is a system trigger
postgres=>
그럼 일반 사용자 로 서 트리거 를 어떻게 사용 하지 않 습 니까?

postgres=> alter table t4 disable trigger user;
구체 적 인 문법 은:

DISABLE TRIGGER [ trigger_name | ALL | USER ]
t1,t2 표 로 돌아 갑 니 다.

postgres=# select * from t1;
 a | b |   c   
---+----+------------
 1 | aa | 2020-11-04
 2 | bb | 2020-11-04
(2 rows)
 
postgres=# select * from t2;
 a | b | c 
---+---+----
 1 | 1 | aa
 2 | 2 | aa
(2 rows)
 
postgres=# insert into t2 (a,b,c) values (3,3,'cc');
INSERT 0 1
postgres=#
t1 에 일치 하지 않 는 기록 을 삽입 하 였 으 나 삽입 에 성공 하 였 습 니 다.

postgres=# alter table t2 enable trigger all;
ALTER TABLE
postgres=# \d t2
         Table "public.t2"
 Column | Type  | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 a   | integer |      | not null |
 b   | integer |      |     |
 c   | text  |      |     |
Indexes:
  "t2_pkey" PRIMARY KEY, btree (a)
Foreign-key constraints:
  "t2_b_fkey" FOREIGN KEY (b) REFERENCES t1(a)
 
postgres=# alter table t2 validate constraint t2_b_fkey;
ALTER TABLE
postgres=#
PostgreSQL 에 일치 하지 않 는 기록 이 보고 되 지 않 았 다 는 것 이 놀 랍 지 않 습 니까?왜 일 까요?
pg 보기constraint:

postgres=# select * from pg_constraint where conname='t2_b_fkey' and conrelid='t2'::regclass;
-[ RECORD 1 ]-+----------
conname    | t2_b_fkey
connamespace | 2200
contype    | f
condeferrable | f
condeferred  | f
convalidated | t
conrelid   | 75202
contypid   | 0
conindid   | 75200
conparentid  | 0
confrelid   | 75194
confupdtype  | a
confdeltype  | a
confmatchtype | s
conislocal  | t
coninhcount  | 0
connoinherit | t
conkey    | {2}
confkey    | {1}
conpfeqop   | {96}
conppeqop   | {96}
conffeqop   | {96}
conexclop   |
conbin    |
consrc    |
 
postgres=#
convalidated 필드 의 값 은 t 입 니 다.이 외부 키 의 제약 이 유효 하 다 는 것 을 나타 냅 니 다.
우리 가 다시 disable 을 사용 하 더 라 도 효과 적 인 것 으로 표 시 됩 니 다.

postgres=# alter table t2 disable trigger all;
ALTER TABLE
postgres=# select * from pg_constraint where conname='t2_b_fkey' and conrelid='t2'::regclass;
-[ RECORD 1 ]-+----------
conname    | t2_b_fkey
connamespace | 2200
contype    | f
condeferrable | f
condeferred  | f
convalidated | t
conrelid   | 75202
contypid   | 0
conindid   | 75200
conparentid  | 0
confrelid   | 75194
confupdtype  | a
confdeltype  | a
confmatchtype | s
conislocal  | t
coninhcount  | 0
connoinherit | t
conkey    | {2}
confkey    | {1}
conpfeqop   | {96}
conppeqop   | {96}
conffeqop   | {96}
conexclop   |
conbin    |
consrc    |
 
postgres=#
이것 은 우리 가(enable)내부 트리거 를 열 때 PostgreSQL 은(vaidate)제약 을 검증 하지 않 기 때문에 데이터 가 충돌 하 는 지 검증 하지 않 는 다 는 것 을 나타 낸다.왜냐하면 외부 키 제약 상태 가 항상 유효 하기 때문이다.
우리 가 해 야 할 일 은 먼저 그것 을 무효 로 만 드 는 것 이다.

postgres=# alter table t2 alter CONSTRAINT t2_b_fkey not valid;
ERROR: ALTER CONSTRAINT statement constraints cannot be marked NOT VALID
##         ,                  
 
postgres=# alter table t2 drop constraint t2_b_fkey;
ALTER TABLE
postgres=# delete from t2 where a in (3);
DELETE 1
postgres=# alter table t2 add constraint t2_b_fkey foreign key (b) references t1(a) not valid;
ALTER TABLE
postgres=# \d t2
         Table "public.t2"
 Column | Type  | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 a   | integer |      | not null |
 b   | integer |      |     |
 c   | text  |      |     |
Indexes:
  "t2_pkey" PRIMARY KEY, btree (a)
Foreign-key constraints:
  "t2_b_fkey" FOREIGN KEY (b) REFERENCES t1(a) NOT VALID
이제 상태 가 무효 임 을 볼 수 있 습 니 다.

postgres=# select * from pg_constraint where conname='t2_b_fkey' and conrelid='t2'::regclass;
-[ RECORD 1 ]-+----------
conname    | t2_b_fkey
connamespace | 2200
contype    | f
condeferrable | f
condeferred  | f
convalidated | f
conrelid   | 75202
contypid   | 0
conindid   | 75200
conparentid  | 0
confrelid   | 75194
confupdtype  | a
confdeltype  | a
confmatchtype | s
conislocal  | t
coninhcount  | 0
connoinherit | t
conkey    | {2}
confkey    | {1}
conpfeqop   | {96}
conppeqop   | {96}
conffeqop   | {96}
conexclop   |
conbin    |
consrc    |
 
postgres=#
데이터 계속 삽입:

postgres=# insert into t2(a,b,c) values (3,3,'cc');
ERROR: insert or update on table "t2" violates foreign key constraint "t2_b_fkey"
DETAIL: Key (b)=(3) is not present in table "t1".
postgres=#
더 놀 라 셨 죠?잘못된 제약 조건 을 만 들 었 습 니 다.PostgreSQL 에 만 알 립 니 다.
모든 줄 기록 이 효과 가 있 는 지 전체 표를 스 캔 하지 마 세 요.새로 삽입 되 거나 업 데 이 트 된 줄 에 대해 서 는 제약 조건 을 만족 시 키 는 지 확인 합 니 다.이것 이 바로 위 에 삽입 하 는 데 실 패 했 습 니 다.
우리 어떻게 해 야 되 지?
1.모든 외부 키 삭제
2.데이터 불 러 오기
3.외부 키 를 다시 만 들 지만 그 상 태 를 무효 로 설정 하여 전체 표를 스 캔 하지 않도록 합 니 다.이후 새로운 데이터 가 검 증 될 것 이다.
4.시스템 부하 가 적 을 때 제약 검증 시작(vaidate the constraints)
다른 방법 은:

postgres=# alter table t2 alter constraint t2_b_fkey deferrable;
ALTER TABLE
postgres=# begin;
BEGIN
postgres=# set constraints all deferred;
SET CONSTRAINTS
postgres=# insert into t2 (a,b,c) values (3,3,'cc');
INSERT 0 1
postgres=# insert into t2 (a,b,c) values (4,4,'dd');
INSERT 0 1
postgres=# insert into t1 (a,b,c) values (3,'cc',now());
INSERT 0 1
postgres=# insert into t1 (a,b,c) values (4,'dd',now());
INSERT 0 1
postgres=# commit;
COMMIT
이렇게 하 는 것 은 좋 지 않 은 점 은 다음 에 제출 할 때 만 작용 하기 때문에 모든 일 을 한 업무 에 맡 겨 야 한다.
본 논문 의 관건 은 다음 의 가설 이 당신 의 데이터 가 틀 렸 다 는 것 을 검증 하 는 것 이다.

postgres=# alter table t2 disable trigger all;
ALTER TABLE
postgres=# insert into t2 (a,b,c) values (5,5,'ee');
INSERT 0 1
postgres=# alter table t2 enable trigger all;
ALTER TABLE
postgres=#
이것 은 새로운 데이터 만 검증 할 수 있 지만 모든 데이터 가 제약 을 만족 시 킬 수 있 는 것 은 아 닙 니 다.

postgres = # insert into t2 (a,b,c) values (6,6,'ff');
ERROR: insert or update on table "t2" violates foreign key constraint "t2_b_fkey"
DETAIL: Key(b) = (6) is not present in table "t1".
postgres = # select * from t2 where b = 5;
a | b | c
---+---+----
5 | 5 | ee
(1 row)
 
postgres = # select * from t1 where a = 5;
a | b | c
---+---+---
(0 rows)
최종 적 으로 해결 하 는 방법 이 있 습 니 다.pg 를 직접 수정 합 니 다.constraint 디 렉 터 리 표.하지만 사용자 에 게 이렇게 하 라 고 건의 합 니 다!

postgres=# delete from t2 where b = 5;
DELETE 1
postgres=# delete from t2 where b = 5;
DELETE 1
postgres=# alter table t2 disable trigger all;
ALTER TABLE
postgres=# insert into t2 values (5,5,'ee');
INSERT 0 1
postgres=# alter table t2 enable trigger all;
ALTER TABLE
postgres=# update pg_constraint set convalidated = false where conname = 't2_b_fkey' and conrelid = 't2'::regclass;
UPDATE 1
postgres=# alter table t2 validate constraint t2_b_fkey;
ERROR: insert or update on table "t2" violates foreign key constraint "t2_b_fkey"
DETAIL: Key (b)=(5) is not present in table "t1".
postgres=#
이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.만약 잘못 이 있 거나 완전히 고려 하지 않 은 부분 이 있다 면 아낌없이 가르침 을 주시 기 바 랍 니 다.

좋은 웹페이지 즐겨찾기