덤프를 복원하는 동안 모든 제한 조건 및 테이블 확인을 사용하지 않도록 설정


19

PostgreSQL 데이터베이스 덤프를 얻었습니다.

pg_dump -U user-name -d db-name -f dumpfile

그런 다음 다른 데이터베이스에서 다음을 사용하여 복원을 진행합니다.

psql X -U postgres  -d db-name-b -f dumpfile

내 문제는 데이터베이스에 참조 제약 조건, 검사 및 트리거가 포함되어 있으며 복원 중에 정보가 검사 순서를 따르지 않는 순서로로드되지 않기 때문에 이러한 검사 중 일부 (특히 검사가 특히 좋아 보이는 검사)가 실패한다는 것입니다. 예를 들어, 테이블에 행을 삽입하는 것은 관련이 없는 다른 테이블에 조건이 있는지 여부를 확인 CHECK하는 plpgsql함수를 호출하는 것과 연관 될 수 있습니다 . 후자의 테이블이 psql전자의 이전 테이블에 의해로드되지 않으면 오류가 발생합니다.

다음은 덤프 된 데이터베이스를 pg_dump복원 할 수없는 SSCCE입니다 .

CREATE OR REPLACE FUNCTION fail_if_b_empty () RETURNS BOOLEAN AS $$
    SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;

CREATE TABLE IF NOT EXISTS a (
     i              INTEGER                    NOT NULL
);

INSERT INTO a(i) VALUES (0),(1);
CREATE TABLE IF NOT EXISTS b (
    i  INTEGER NOT NULL
);
INSERT INTO b(i) VALUES (0);

ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty());

덤프 복원 중에 이러한 제한 조건을 모두 사용 불가능하게하고 (명령 행에서) 나중에 다시 사용 가능하게하는 방법이 있습니까? PostgreSQL 9.1을 실행하고 있습니다.


AFAIK에 대한 옵션 -X-d옵션 이 없습니다 pg_dump. pg_dump덤프 생산 이다 빈 DB에 복원 할를.
dezso

1
@dezso 맞아요, 이것들은 오타였습니다. 질문을 업데이트했습니다. 슬프게도 덤프 내가 인용 한 이유로 인해 빈 DB에서 복원 할 수 없습니다 .
Marcus Junius Brutus

이 질문은 당신의 Postgres 버전을 필요로합니다. 내가 지적하지 않고서는 분명해야합니다.
Erwin Brandstetter

나는 9.6에서 같은 문제를 재현 할 수 @ErwinBrandstetter 참조 bugs.debian.org/cgi-bin/bugreport.cgi?bug=859033을 또 다른 예 (더 실제, 약간 큰, MWE)에 대한
mirabilos

1
@mirabilos : 말하고 싶습니다 : CHECK제약 조건 에서 다른 테이블을 참조하는 함수를 사용하면 공식적으로 지원되지 않고 허용되므로 모든 보증이 무효화됩니다. 그러나 CHECK제약 조건을 선언하면 NOT VALID모든면에서 나를 위해 일했습니다. 내가 만지지 않은 코너 케이스가있을 수 있습니다 ...
Erwin Brandstetter 16:31의

답변:


17

따라서 CHECK제약 조건 에서 다른 테이블을 찾습니다 .

CHECK제한 조건은 IMMUTABLE점검 을 실행해야 합니다. 한 번에 한 행씩 OK를 통과 하는 것은 언제 라도 OK를 통과해야합니다 . 이것이 CHECKSQL 표준에서 제약 조건이 정의 된 방식 입니다. 이것이 또한이 제한에 대한 이유이기도합니다 ( 문서 당 ) :

현재 CHECK식은 하위 쿼리를 포함하거나 현재 행의 열 이외의 변수를 참조 할 수 없습니다.

이제 CHECK제약 조건의 표현식은 사용자 정의 함수조차도 함수를 사용할 수 있습니다. 그것들은 IMMUTABLE기능 으로 제한되어야 하지만 Postgres는 현재 이것을 시행하지 않습니다. pgsql-hackers에 관한관련 토론에 따르면 , 한 가지 이유는 현재 시간에 대한 참조를 허용하는 것이지, 이는 IMMUTABLE본질적 으로 아닙니다 .

그러나 CHECK제약 조건이 작동 하는 방식을 완전히 위반하는 다른 테이블의 행을 찾고 있습니다. 나는 pg_dump이것을 제공 하지 못하는 것에 놀라지 않습니다 .

다른 테이블에서 수표를 트리거 (올바른 도구)로 옮기면 최신 버전의 Postgres에서 작동합니다.

PostgreSQL 9.2 이상

위의 내용은 모든 Postgres 버전에 해당되지만 Postgres 9.2에는 상황에 도움이되는 몇 가지 도구가 도입되었습니다.

pg_dump 옵션 --exclude-table-data

간단한 해결책은 위반 테이블에 대한 데이터없이 db를 다음과 같이 덤프하는 것입니다.

--exclude-table-data=my_schema.my_tbl

그런 다음 덤프 끝에이 테이블의 데이터 만 추가하십시오.

--data-only --table=my_schema.my_tbl

그러나 동일한 테이블에서 다른 제약 조건과 관련된 문제가 발생할 수 있습니다. 더있다 더 나은 솔루션 :

NOT VALID

NOT VALID제약 조건에 대한 수정자가 있습니다 . v9.1의 FK 제약에만 사용할 수 있지만 CHECK9.2의 제약 으로 확장되었습니다 . 설명서 당 :

제한 조건이로 표시 NOT VALID되면 테이블의 모든 행이 제한 조건을 만족하는지 검증하기위한 잠재적으로 긴 초기 점검이 생략됩니다. 구속 조건은 계속해서 후속 삽입 또는 업데이트에 대해 시행됩니다 ...]

일반 postgres 덤프 파일은 세 개의 "섹션"으로 구성됩니다.

  • pre_data
  • data
  • post-data

Postgres 9.2는 또한으로 섹션을 별도로 덤프하는 옵션을 도입 -- section=sectionname했지만 현재 문제를 해결하지는 못합니다.

여기 흥미로운 곳이 있습니다. 설명서 당 :

사후 데이터 항목에는 검증 된 점검 제한 조건 이외 의 색인, 트리거, 규칙 및 제한 조건 정의가 포함됩니다 . 사전 데이터 항목에는 다른 모든 데이터 정의 항목이 포함됩니다.

대담한 강조 광산.
문제가되는 CHECK구속 조건을로 변경하면 NOT VALID구속 조건이 post-data섹션으로 이동합니다 . 삭제 및 재생성 :

ALTER TABLE a DROP CONSTRAINT a_constr_1;
ALTER TABLE a ADD  CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()) NOT VALID;

문제가 해결 될 것입니다. 제약 조건을 해당 상태로 유지할 수도 있습니다. 실제로 수행하는 작업을 더 잘 반영하기 때문입니다. 새 행을 확인하지만 기존 데이터에 대해서는 보장하지 않습니다. NOT VALID점검 제한 조건 에는 아무런 문제가 없습니다 . 원하는 경우 나중에 확인할 수 있습니다.

ALTER TABLE a VALIDATE CONSTRAINT a_constr_1;

그러나 당신은 현재 상태로 돌아갑니다.


복원 할 수없는 데이터베이스를 보여주는 SSCCE로 질문을 풍부하게했습니다. 나는 당신이 말하는 것을 얻었지만, 왜 SSCCE에서 보여준 문제가있는 상황을 점검 대신 트리거로 재현 할 수 없는지 알 수 없습니다.
Marcus Junius Brutus

1
@MarcusJuniusBrutus : 작성시 이미 테이블에있는 모든 행에 대해 점검 제한 조건이 평가되기 때문에 트리거는 정의 된 이벤트에서만 실행됩니다.
Erwin Brandstetter 19

트리거를 사용하여 정확한 스키마 논리를 재현했습니다. 트리거를 사용하면 복원이 실제로 성공하지만 이는 pg_dump덤프 파일의 끝에 트리거를 추가 한다는 사실 때문일 뿐이며 명령의 CHECK일부로 s를 작성합니다 CREATE TABLE. 따라서 pg_dump공구가 다른 접근 방식을 사용한 경우 수표 케이스에도 복원이 성공했을 수 있습니다 . 트리거를 사용하면 왜 DDL이 OK인지 알 수 없지만 두 경우 모두 동일한 논리가 구현되어 검사를 사용하면 OK가 아닙니다 (자신의 대답에서 트리거를 사용하여 스크립트 버전을 볼 수 있음).
Marcus Junius Brutus

1
@MarcusJuniusBrutus : pg_dump확인 제약 조건에 대해 다른 DDL을 생성해야한다고 생각 되면 (예 : 끝 부분에 모두 추가) Postgres 메일 링리스트에 개선 요청으로 게시해야합니다. 그러나 나는 Erwin이 당신이 의도하지 않은 것에 대한 검사 제한을 잘못 사용하고 있다는 것에 동의합니다. 따라서 가까운 장래에 변경 요청이 구현 될 것으로 기대하지는 않습니다. Btw : SSCCE는 두 테이블 사이의 외래 키를 사용하여 더 잘 모델링됩니다.
a_horse_with_no_name

@MarcusJuniusBrutus : Postgres 9.2 이상에 대한 솔루션이 있습니다. 따라서 Postgres 버전이 중요한 이유입니다. 어쩌면 업그레이드가 당신을위한 옵션일까요? 포스트 그레스 9.1 ... 어쨌든 노화
어윈 Brandstetter

2

pg_dump덤프를 작성하는 방식 때문인 것 같습니다 . 실제 덤프 CHECK를 보면 CREATE TABLE명령 의 일부인 구문을 사용하여 덤프 파일에 제약 조건이 있음을 알았습니다 .

CREATE TABLE a (
    i integer NOT NULL,
    CONSTRAINT a_constr_1 CHECK (fail_if_b_empty())
);      

이는 테이블 a이나 테이블에 b데이터가 있기 전에 점검이 이루어 지므로 데이터베이스 복원시 실패를 만듭니다 . 그러나 덤프 파일이 편집되고 CHECK덤프 파일 끝에 다음 구문을 대신 사용하여 추가됩니다.

ALTER TABLE a ADD CONSTRAINT a_constr_1 CHECK (fail_if_b_empty()); 

... 복원에 문제가 없습니다.

TRIGGER다음 스크립트에서와 같이 똑같은 논리를 구현할 수 있습니다 .

CREATE OR REPLACE FUNCTION fail_if_b_empty (
    ) RETURNS BOOLEAN AS $$
    SELECT EXISTS (SELECT 1 FROM b)
$$ LANGUAGE SQL;

DROP TABLE IF EXISTS a;

CREATE TABLE IF NOT EXISTS a (
    i   INTEGER   NOT NULL
);

INSERT INTO a(i) VALUES (0),(1);

CREATE TABLE IF NOT EXISTS b (
    i  INTEGER NOT NULL
);

INSERT INTO b(i) VALUES (0);

CREATE TRIGGER tr1 AFTER INSERT OR UPDATE ON a
FOR EACH ROW
EXECUTE PROCEDURE fail_if_b_empty();  

그러나이 경우 pg_dump덤프 파일의 끝에 트리거가 CREATE TABLE작성되고 (확인의 경우와 같은 명령문이 아닌 ) 복원이 성공합니다.


예제에서 트리거가 표시되지 않음
Sam Watkins

1
@SamWatkins 복사-붙여 넣기 오류가 수정되었습니다.
Marcus Junius Brutus 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.