PostgreSQL 덤프를 이전 또는 최신 PostgreSQL로 옮기기
pg_dump나 pg_dumpall의 일반 덤프(.sql 또는 .sql.gz)를 놓으면, 어느 버전이 쓴 덤프든 PostgreSQL 13~18에서 불러와지는 스크립트 하나를 받아요. IDENTITY, enum, 배열, jsonb는 그대로이고, 확장 기능의 타입은 텍스트가 되며, 모든 변경은 보고서에 나와요.
18개 행 변환, 수정 없음, 거부 없음
shop_2024_postgres.sql의 테이블PostgreSQL 18.6 덤프 · pg_dump(으)로 작성됨 · utf8mb4
customers8개 행
8개 열 id integer not null name text not null email text not null country varchar(2) not null is_active boolean not null tags text[] not null signed_up date created_at timestamptz(6) not null orders10개 행
10개 열 id integer not null customer_id integer not null status order_status not null total numeric(10,2) not null items smallint not null ordered_at timestamp(6) not null shipped_at timestamp(6) note text details jsonb delivery interval
변환되지 않음
- 뷰 paid_orders
데이터베이스마다 이 객체를 자체 언어로 작성해요. PostgreSQL에 맞게 다시 작성하세요.
-- Written by IntoSQL from a PostgreSQL dump. Load it with: psql -v ON_ERROR_STOP=1 -f <file>
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET synchronous_commit = off;
SET maintenance_work_mem = '512MB';
CREATE TYPE order_status AS ENUM ('pending', 'paid', 'shipped', 'cancelled');
CREATE TABLE customers (
id integer GENERATED BY DEFAULT AS IDENTITY NOT NULL,
name text NOT NULL,
email text NOT NULL,
country varchar(2) DEFAULT 'US' NOT NULL,
is_active boolean DEFAULT true NOT NULL,
tags text[] DEFAULT '{}' NOT NULL,
signed_up date,
created_at timestamptz(6) DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE orders (
id integer GENERATED BY DEFAULT AS IDENTITY NOT NULL,
customer_id integer NOT NULL,
status order_status DEFAULT 'pending' NOT NULL,
total numeric(10,2) NOT NULL,
items smallint DEFAULT 1 NOT NULL,
ordered_at timestamp(6) NOT NULL,
shipped_at timestamp(6),
note text,
details jsonb,
delivery interval,
CONSTRAINT orders_total_check CHECK (total >= (0))
);
COPY customers (id, name, email, country, is_active, tags, signed_up, created_at) FROM stdin;
1 Ana Martínez ana@example.com MX t {vip} 2023-01-15 2023-01-15 10:24:00+00
2 Zoë Müller zoe@example.de DE t {} 2023-02-03 2023-02-03 08:11:42+00
3 José Peña jose@example.es ES f {wholesale,"late payer"} 2023-03-21 2023-03-21 19:05:17+00
4 李雷 lilei@example.cn CN t {} 2023-05-09 2023-05-09 02:40:00+00
5 Noah O'Brien noah@example.ie IE t {} \N 2023-06-30 14:00:00+00
6 Amélie Laurent amelie@example.fr FR t {vip} 2024-01-02 2024-01-02 09:30:00+00
7 Ravi Patel ravi@example.in IN f {} 2024-02-29 2024-02-29 23:59:59+00
8 Sofia Rossi 🌻 sofia@example.it IT t {} 2024-04-12 2024-04-12 12:12:12+00
\.
COPY orders (id, customer_id, status, total, items, ordered_at, shipped_at, note, details, delivery) FROM stdin;
1 1 shipped 129.90 3 2024-03-01 10:00:00 2024-03-02 16:30:00 \N {"gift": false} 1 day 06:30:00
2 2 paid 54.00 1 2024-03-02 11:15:00 \N Gift wrap 🎁 {"gift": true, "wrap": "red"} \N
3 1 cancelled 12.50 1 2024-03-03 09:45:00 \N Customer changed their mind \N \N
4 4 shipped 980.00 12 2024-03-05 02:10:00 2024-03-07 08:00:00 请小心轻放 {"fragile": true} 2 days 05:50:00
5 5 pending 45.75 2 2024-03-08 17:20:00 \N Leave at the door; ring twice \N \N
6 6 shipped 310.40 5 2024-03-10 13:00:00 2024-03-11 09:00:00 Fragile: "glass" {"fragile": true} 20:00:00
7 8 paid 76.20 2 2024-03-11 18:45:00 \N \N \N \N
8 2 shipped 19.99 1 2024-03-12 08:00:00 infinity Shipped date set to infinity by an old import \N \N
9 3 shipped 64.00 2 2024-03-14 15:30:00 2024-03-15 10:00:00 Two parcels {"parcels": [1, 2]} 18:30:00
10 7 paid 1499.00 1 2024-03-15 21:05:00 \N C:\\Users\\ravi\\invoice.pdf \N \N
\.
-- Keys, indexes and constraints, after the rows so each builds once.
CREATE UNIQUE INDEX customers_email_key ON customers (email);
CREATE UNIQUE INDEX customers_pkey ON customers (id);
CREATE UNIQUE INDEX orders_pkey ON orders (id);
CREATE INDEX idx_orders_customer ON orders (customer_id);
CREATE INDEX idx_orders_status_date ON orders (status, ordered_at);
ALTER TABLE customers ADD CONSTRAINT customers_email_key UNIQUE USING INDEX customers_email_key;
ALTER TABLE customers ADD CONSTRAINT customers_pkey PRIMARY KEY USING INDEX customers_pkey;
ALTER TABLE orders ADD CONSTRAINT orders_pkey PRIMARY KEY USING INDEX orders_pkey;
ALTER TABLE orders ADD CONSTRAINT orders_customer_id_fkey FOREIGN KEY (customer_id) REFERENCES customers (id) NOT VALID;
DO $f$ BEGIN
ALTER TABLE orders VALIDATE CONSTRAINT orders_customer_id_fkey;
EXCEPTION WHEN foreign_key_violation THEN
RAISE WARNING 'foreign key % has rows without a parent: it stays NOT VALID, and new rows are checked', 'orders_customer_id_fkey';
END $f$;
SELECT setval(pg_get_serial_sequence('customers', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM customers)::numeric, 0) + 1, 1001), 2147483647)::bigint, false);
COMMENT ON TABLE customers IS 'People who bought at least once';
SELECT setval(pg_get_serial_sequence('orders', 'id'), LEAST(GREATEST(COALESCE((SELECT max(id) FROM orders)::numeric, 0) + 1, 5001), 2147483647)::bigint, false);
수정 사항
수정할 부분이 없었어요.
확인 필요
- 뷰, 트리거, 루틴, 이벤트 1개가 변환되지 않았어요. 보고서에 각각 나와 있어요. PostgreSQL에서 직접 다시 만드세요.
- orders의 인덱스 idx_orders_details은(는) PostgreSQL용으로 쓸 수 없는 식을 사용해서(a gin index) 만들지 않았어요. 쿼리에 필요하면 인덱스를 직접 만드세요.
파일은 이 컴퓨터에서 변환되고 업로드되지 않아요.
다른 샘플:
파일과 스크립트에서 바뀌는 점
각 행은 변환기가 적용하는 규칙이며, 규칙이 데이터를 바꿀 때 보고서에 쓰는 줄이 함께 나와요.
varchar(n), char(n), text
같은 타입
같은 타입이고 길이도 같아요.
numeric(p,s), numeric without a precision, NaN and Infinity
같은 타입과 값
같은 타입이에요. 모든 자릿수를 덤프에 적힌 그대로 복사해요.
money
numeric(19,2)
money의 표기는 서버의 lc_monetary에 따라 달라서, 금액을 통화 기호 없이 숫자로 유지해요. 그래서 대상의 로캘과 상관없이 불러와져요.
보고서 줄: type_replaced
enum types
같은 enum 타입, 테이블보다 먼저 만듦
레이블은 순서를 유지해요.
enum columns holding values outside their labels
체크 제약 없는 text
타입이 이 값들을 거부하므로 열은 text가 되어 모든 값을 유지해요.
보고서 줄: enum_check_skipped
composite and range types the dump defines, extension types (citext, hstore, ltree, PostGIS) and multiranges
PostgreSQL의 텍스트를 담은 text
스크립트는 확장도 복합 타입도 만들지 않아서 각 값은 PostgreSQL이 쓴 텍스트를 유지해요. 불러온 뒤 타입을 만들고 열을 변경하세요.
보고서 줄: type_replaced
citext
text, 정확히 비교
스크립트는 citext 확장을 만들지 않아서 이 열들은 텍스트를 정확히 비교해요. 불러온 뒤 확장을 만들고 열을 되돌리세요.
보고서 줄: case_insensitive_collation
json, jsonb
같은 타입
json은 적힌 그대로의 텍스트를 유지하고, jsonb는 서버가 정규화한 값을 유지해요.
timestamp with time zone
timestamptz, 같은 시점
각 값은 덤프에 적힌 오프셋을 유지하므로 어느 시간대에서든 같은 시점이에요.
time, time with time zone
같은 타입
24:00:00을 포함해 같은 타입이에요.
infinity, -infinity and BC dates
유지
PostgreSQL은 이 값을 그대로 담아요.
NaN and Infinity in numeric, real and double precision
유지
PostgreSQL은 이 값을 그대로 담아요.
generated columns
같은 생성 열
같은 수식을 대상이 계산해요.
generated columns with functions IntoSQL doesn't write
값을 담은 일반 열
IntoSQL이 쓸 수 없는 수식은 덤프의 값을 담은 일반 열로 남고 보고서에 한 줄 기록돼요.
보고서 줄: generated_not_translated
defaults with functions IntoSQL doesn't write
기본값 없음
IntoSQL이 쓸 수 없는 기본값은 제외하고 보고해요.
보고서 줄: default_not_translated
CHECK constraints with functions IntoSQL doesn't write
만들지 않음
IntoSQL이 쓸 수 없는 체크 제약은 제외하고 보고해요.
보고서 줄: check_skipped
CHECK ... NOT VALID
행 다음에 NOT VALID로 추가
기존 행은 검사된 적이 없어서 체크 제약을 행 다음에 여전히 NOT VALID 상태로 추가해요.
gin, gist, brin and hash indexes, partial and expression indexes
만들지 않음
IntoSQL은 열에 대한 b-tree 인덱스를 써요. 다른 인덱스는 불러온 뒤 다시 만드세요.
보고서 줄: index_skipped
foreign keys to tables the dump doesn't create
만들지 않음
키는 없는 테이블을 가리킬 수 없어요.
보고서 줄: foreign_key_skipped
NOT NULL columns with values that become NULL
NOT NULL 제거
값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요.
보고서 줄: not_null_relaxed
partitioned tables
모든 파티션의 행을 담은 하나의 테이블
행은 같아요. 필요하면 테이블을 다시 파티션으로 나누세요.
보고서 줄: partitions_dropped
views, functions, procedures, triggers, rules, policies, extensions and types other than enums
보고서에 나열
IntoSQL은 테이블과 행을 변환해요. 나머지는 직접 다시 만들 수 있도록 나열해요.
보고서 줄: not_converted_objects
dumps without CREATE TABLE (--data-only)
값으로 판단한 타입
데이터만 있는 덤프에는 행만 있어서 타입을 값으로 판단해요.
보고서 줄: no_schema
expressions in INSERT values
NULL
데이터베이스를 실행하지 않는 변환기는 이 식을 계산할 수 없어요.
보고서 줄: expression_value
types IntoSQL doesn't know
text
텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요.
보고서 줄: unknown_type
text that isn't valid in its encoding
잘못된 바이트를 대체 문자로
PostgreSQL 텍스트는 올바른 UTF-8이어야 해요.
보고서 줄: invalid_utf8_replaced
text decoded twice (ñ)
그대로 복사
덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요.
보고서 줄: mojibake_suspected
| 파일에서 | 스크립트에서 | 보고서 줄 |
|---|---|---|
| varchar(n), char(n), text | 같은 타입같은 타입이고 길이도 같아요. | |
| numeric(p,s), numeric without a precision, NaN and Infinity | 같은 타입과 값같은 타입이에요. 모든 자릿수를 덤프에 적힌 그대로 복사해요. | |
| money | numeric(19,2)money의 표기는 서버의 lc_monetary에 따라 달라서, 금액을 통화 기호 없이 숫자로 유지해요. 그래서 대상의 로캘과 상관없이 불러와져요. | type_replaced |
| enum types | 같은 enum 타입, 테이블보다 먼저 만듦레이블은 순서를 유지해요. | |
| enum columns holding values outside their labels | 체크 제약 없는 text타입이 이 값들을 거부하므로 열은 text가 되어 모든 값을 유지해요. | enum_check_skipped |
| composite and range types the dump defines, extension types (citext, hstore, ltree, PostGIS) and multiranges | PostgreSQL의 텍스트를 담은 text스크립트는 확장도 복합 타입도 만들지 않아서 각 값은 PostgreSQL이 쓴 텍스트를 유지해요. 불러온 뒤 타입을 만들고 열을 변경하세요. | type_replaced |
| citext | text, 정확히 비교스크립트는 citext 확장을 만들지 않아서 이 열들은 텍스트를 정확히 비교해요. 불러온 뒤 확장을 만들고 열을 되돌리세요. | case_insensitive_collation |
| json, jsonb | 같은 타입json은 적힌 그대로의 텍스트를 유지하고, jsonb는 서버가 정규화한 값을 유지해요. | |
| timestamp with time zone | timestamptz, 같은 시점각 값은 덤프에 적힌 오프셋을 유지하므로 어느 시간대에서든 같은 시점이에요. | |
| time, time with time zone | 같은 타입24:00:00을 포함해 같은 타입이에요. | |
| infinity, -infinity and BC dates | 유지PostgreSQL은 이 값을 그대로 담아요. | |
| NaN and Infinity in numeric, real and double precision | 유지PostgreSQL은 이 값을 그대로 담아요. | |
| generated columns | 같은 생성 열같은 수식을 대상이 계산해요. | |
| generated columns with functions IntoSQL doesn't write | 값을 담은 일반 열IntoSQL이 쓸 수 없는 수식은 덤프의 값을 담은 일반 열로 남고 보고서에 한 줄 기록돼요. | generated_not_translated |
| defaults with functions IntoSQL doesn't write | 기본값 없음IntoSQL이 쓸 수 없는 기본값은 제외하고 보고해요. | default_not_translated |
| CHECK constraints with functions IntoSQL doesn't write | 만들지 않음IntoSQL이 쓸 수 없는 체크 제약은 제외하고 보고해요. | check_skipped |
| CHECK ... NOT VALID | 행 다음에 NOT VALID로 추가기존 행은 검사된 적이 없어서 체크 제약을 행 다음에 여전히 NOT VALID 상태로 추가해요. | |
| gin, gist, brin and hash indexes, partial and expression indexes | 만들지 않음IntoSQL은 열에 대한 b-tree 인덱스를 써요. 다른 인덱스는 불러온 뒤 다시 만드세요. | index_skipped |
| foreign keys to tables the dump doesn't create | 만들지 않음키는 없는 테이블을 가리킬 수 없어요. | foreign_key_skipped |
| NOT NULL columns with values that become NULL | NOT NULL 제거값을 NULL로 바꿔야 했던 열은 NOT NULL을 유지할 수 없어요. 유지하면 불러오기가 멈춰요. | not_null_relaxed |
| partitioned tables | 모든 파티션의 행을 담은 하나의 테이블행은 같아요. 필요하면 테이블을 다시 파티션으로 나누세요. | partitions_dropped |
| views, functions, procedures, triggers, rules, policies, extensions and types other than enums | 보고서에 나열IntoSQL은 테이블과 행을 변환해요. 나머지는 직접 다시 만들 수 있도록 나열해요. | not_converted_objects |
| dumps without CREATE TABLE (--data-only) | 값으로 판단한 타입데이터만 있는 덤프에는 행만 있어서 타입을 값으로 판단해요. | no_schema |
| expressions in INSERT values | NULL데이터베이스를 실행하지 않는 변환기는 이 식을 계산할 수 없어요. | expression_value |
| types IntoSQL doesn't know | text텍스트는 어떤 값이든 담아요. 불러온 뒤 타입을 바꾸세요. | unknown_type |
| text that isn't valid in its encoding | 잘못된 바이트를 대체 문자로PostgreSQL 텍스트는 올바른 UTF-8이어야 해요. | invalid_utf8_replaced |
| text decoded twice (ñ) | 그대로 복사덤프에 정확히 이 문자들이 있으므로 그대로 복사하고, 보고서에서 알려 줘요. | mojibake_suspected |
스크립트를 PostgreSQL에 불러오기
스크립트는 테이블을 만들고 행을 복사한 다음 키, 인덱스, 외래 키를 추가해요. 그래서 빨리 불러오고 첫 오류에서 멈춰요.
psql -v ON_ERROR_STOP=1 -d mydb -f postgresql.postgresql.sql외래 키는 NOT VALID로 추가한 다음 검증해요. 어떤 행이 존재하지 않는 행을 가리키면, 중간에 실패하지 않고 어떤 제약인지 알려 줘요.
큰 덤프는 데이터베이스를 먼저 만들고, 서버와 같은 컴퓨터에서 psql로 스크립트를 실행하세요.
IntoSQL Pro는 데스크톱 앱이나 명령줄에서 파일을 PostgreSQL에 바로 불러와요. 스크립트를 따로 만들 필요가 없어요.
좋은 결과를 위한 PostgreSQL 덤프 방법
변환기는 덤프에 담긴 내용을 읽어요. 다음 옵션을 쓰면 더 많은 데이터가 덤프에 남아요:
- pg_dump의 기본값인 --format=plain은 SQL을 써요. custom 또는 directory 아카이브(-Fc, -Fd)는 데이터베이스 서버 없이 pg_restore -f dump.sql로 SQL이 돼요.
- --no-owner --no-privileges는 어차피 변환기가 건너뛰는 역할과 권한을 빼서 덤프가 작아져요.
- pg_dumpall은 모든 데이터베이스를 한 파일에 덤프해요. 각 데이터베이스의 테이블 이름에 그 데이터베이스 이름이 붙어서 충돌하지 않아요.
변환되지 않는 것
뷰, 트리거, 프로시저, 함수 등 PostgreSQL 자체 언어로 작성된 객체는 몰래 빠지지 않고 보고서에 이름으로 나와요. 불러올 PostgreSQL 버전에서 확인한 뒤 다시 만들 수 있어요.
PostgreSQL 버전 간 이동 질문
여기에 답이 없나요? 문의 페이지로 연락하시면 담당자가 답장해요. 문의 페이지
덤프가 업로드되나요?
아니요. 변환기는 브라우저에서 실행되고 디스크의 덤프를 조각조각 읽으므로, 덤프가 컴퓨터 밖으로 나가지 않아요. 데스크톱 앱과 명령줄도 컴퓨터에서 변환해요.
덤프는 얼마나 커도 되나요?
변환기는 덤프 전체를 메모리에 올리지 않아요. 파일을 범위별로 두 번 읽고, 읽는 대로 스크립트를 써요. 수 GB 덤프도 브라우저, 데스크톱 앱, 명령줄에서 변환돼요.
pg_dump -Fc 아카이브도 읽나요?
직접은 읽지 않아요. custom 아카이브는 바이너리 형식이에요. pg_restore -f dump.sql dump.backup을 실행하면 서버에 연결하지 않고 변환기가 읽는 일반 SQL로 바뀌어요. 아카이브를 받으면 변환기가 이렇게 알려 줘요.
어떤 PostgreSQL 버전의 덤프를 읽나요?
PostgreSQL 10 이상에서 pg_dump와 pg_dumpall로 만든, COPY 또는 INSERT 행이 담긴 덤프예요. 모든 테스트 덤프는 PostgreSQL 13과 18에서 만들고 원본과 셀 단위로 비교해요.
serial과 identity 값은 유지되나요?
네. serial과 identity 열은 identity 열로 남고, 모든 행은 id를 유지해요. 각 카운터는 덤프의 시퀀스가 도달한 값부터 이어져요.
배열, enum 등 PostgreSQL 타입은 어떻게 되나요?
money를 빼면 배열, 범위, json과 jsonb, 비트 문자열은 그대로예요. enum 타입은 레이블과 함께 다시 만들어요. 확장이 제공하는 타입(citext, hstore, PostGIS)과 복합 타입은 텍스트가 되고, 보고서에 어떤 열인지 나와요.
함수, 트리거, 뷰는 어떻게 되나요?
변환하지 않고 보고서에 이름으로 나열하므로, 테이블을 불러온 뒤 다시 만들 수 있어요. NOT VALID 체크 제약은 행 다음에 여전히 NOT VALID 상태로 추가해요.
스크립트는 어떤 PostgreSQL 버전에서 불러올 수 있나요?
덤프를 만든 버전과 상관없이 PostgreSQL 13부터 18까지예요. 모든 버전에서 같은 스크립트를 불러올 수 있고, 문제가 생기면 첫 오류에서 멈춰요.