Backup hanya separuh dari janji — separuh lainnya adalah memulihkannya saat dibutuhkan. Untuk file hasil pg_dump format custom dan directory, alat pemulihnya adalah pg_restore: program yang membaca daftar isi arsip, lalu membangun ulang objek dan datanya di database tujuan. Berbeda dengan memutar file SQL polos lewat psql, pg_restore tahu persis apa saja yang ada di dalam arsip — dan pengetahuan itu membuka kemampuan yang mustahil pada file teks: melihat daftar isi, memulihkan satu tabel saja, memisahkan skema dari data, sampai menjalankan pemulihan dengan beberapa proses paralel. Chapter ini menuntun siklus lengkapnya di atas data latihan yang sama dengan chapter pg_dump
, termasuk jebakan constraint yang kerap menjegal restore selektif.
Alat yang Tepat untuk Formatnya #
Aturan pertama pg_restore sudah tersirat di namanya: program ini bekerja dengan arsip — format custom (-Fc) dan directory (-Fd) — bukan file teks. Pilihan alat pemulih mengikuti format dump yang Anda simpan:
| Format dump | Alat pemulih | Perintah pemulih |
|---|---|---|
plain (-Fp, bawaan) | psql | psql -d db_baru -f backup.sql |
custom (-Fc) | pg_restore | pg_restore -d db_baru backup.dump |
directory (-Fd) | pg_restore | pg_restore -d db_baru folder_dump/ |
file cluster pg_dumpall | psql | psql -d postgres -f cluster.sql |
Siklus Lengkap: Cadangkan, Pulihkan, Verifikasi #
Empat tahap siklus yang sehat selalu berbentuk lingkaran: siapkan data sumber, cadangkan dengan -Fc, pulihkan ke database baru, lalu verifikasi hasilnya sebelum menyebut pekerjaan selesai. File SQL pertama membangun sumbernya — tiga tabel Toko Maju Jaya yang sama dengan chapter sebelumnya:
-- Database sumber untuk siklus backup-restore: tiga tabel berelasi.
CREATE TABLE produk (
id integer PRIMARY KEY,
nama varchar(40),
harga numeric(10,2)
);
INSERT INTO produk (id, nama, harga) VALUES
(1, 'Kopi Gayo 250g', 45000),
(2, 'Teh Melati 100g', 15000),
(3, 'Gula Aren 500g', 32000),
(4, 'Beras Pandan 1kg', 68000),
(5, 'Susu Kental 375g', 21000);
CREATE TABLE pelanggan (
id integer PRIMARY KEY,
nama varchar(40),
email varchar(60)
);
INSERT INTO pelanggan (id, nama, email) VALUES
(1, 'Budi Santoso', '[email protected]'),
(2, 'Siti Aminah', '[email protected]'),
(3, 'Rina Wijaya', '[email protected]');
CREATE TABLE pesanan (
id integer PRIMARY KEY,
pelanggan_id integer REFERENCES pelanggan(id),
produk_id integer REFERENCES produk(id),
qty integer
);
INSERT INTO pesanan (id, pelanggan_id, produk_id, qty) VALUES
(101, 1, 1, 2),
(102, 2, 3, 1),
(103, 1, 4, 5),
(104, 3, 2, 3);
SELECT (SELECT count(*) FROM produk) AS jumlah_produk,
(SELECT count(*) FROM pelanggan) AS jumlah_pelanggan,
(SELECT count(*) FROM pesanan) AS jumlah_pesanan;Output yang Dihasilkan:
CREATE TABLE
INSERT 0 5
CREATE TABLE
INSERT 0 3
CREATE TABLE
INSERT 0 4
jumlah_produk | jumlah_pelanggan | jumlah_pesanan
---------------+------------------+----------------
5 | 3 | 4
(1 row)Skrip kedua menjalani tiga tahap berikutnya dalam satu tarikan:
#!/bin/bash
pg_isready -q || { echo "server tidak siap"; exit 1; }
# Tahap 1: cadangkan database sumber dalam format custom.
# (Ukuran berkas sengaja tidak ditampilkan: format custom menyisipkan
# stempel waktu pembuatan sehingga ukurannya berubah tiap eksekusi.)
pg_dump -Fc "$PGDATABASE" -f backup_latihan.dump
pg_restore --list backup_latihan.dump | grep -c 'TABLE DATA'
# Tahap 2: siapkan database tujuan yang kosong.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS pulih_latihan WITH (FORCE)" \
-c "CREATE DATABASE pulih_latihan" > /dev/null
# Tahap 3: pulihkan seluruh isi archive.
pg_restore -d pulih_latihan backup_latihan.dump
echo "exit pg_restore: $?"
# Tahap 4: verifikasi -- jumlah dan isi harus identik dengan sumbernya.
psql -X -d pulih_latihan -c "SELECT (SELECT count(*) FROM produk) AS produk,
(SELECT count(*) FROM pelanggan) AS pelanggan,
(SELECT count(*) FROM pesanan) AS pesanan"
psql -X -d pulih_latihan -c "SELECT ps.id, pl.nama AS pelanggan, pr.nama AS produk, ps.qty
FROM pesanan ps
JOIN pelanggan pl ON pl.id = ps.pelanggan_id
JOIN produk pr ON pr.id = ps.produk_id
ORDER BY ps.id"Output yang Dihasilkan:
3
exit pg_restore: 0
produk | pelanggan | pesanan
--------+-----------+---------
5 | 3 | 4
(1 row)
id | pelanggan | produk | qty
-----+--------------+------------------+-----
101 | Budi Santoso | Kopi Gayo 250g | 2
102 | Siti Aminah | Gula Aren 500g | 1
103 | Budi Santoso | Beras Pandan 1kg | 5
104 | Rina Wijaya | Teh Melati 100g | 3
(4 rows)Empat tahap itu layak dibedah satu per satu:
- Tahap 1 (
pg_dump -Fc ... -f backup_latihan.dump): arsip custom tercipta;pg_restore --list | grep -c 'TABLE DATA'menghitung tiga entri data dalam daftar isi arsip (TOC) — produk, pelanggan, dan pesanan. Ukuran berkasnya sendiri tidak ditampilkan karena format custom menyisipkan stempel waktu pembuatan, sehingga ukurannya berbeda beberapa byte antar eksekusi walau isinya identik. - Tahap 2 (
DROP DATABASE IF EXISTS ... WITH (FORCE)): database tujuan dibuat segar. Pola ini membuat skrip aman dijalankan berulang — sisa restore lama dibuang lebih dulu, bukan ditumpuk. - Tahap 3 (
pg_restore -d pulih_latihan ...): seluruh isi arsip dipulihkan berurutan sesuai daftar isinya, dan exit code0dicatat.pg_restoreberhasil dengan senyap — tidak ada deretanCREATE TABLEseperti padapsql; kegagalan justru yang berbicara lewatstderrdan exit code bukan nol. - Tahap 4 (dua query verifikasi): jumlah baris
5 / 3 / 4sama dengan sumbernya, dan join tiga tabel mengembalikan empat pesanan dengan nama pelanggan dan produk yang benar — join yang berhasil membuktikan foreign key ikut terpulihkan, bukan hanya tabel dan datanya.
Melihat Isi Archive dengan –list #
Kemampuan pertama yang hanya dimiliki arsip: isi file bisa didaftar tanpa memulihkan apa pun. Opsi --list mencetak table of contents (TOC) — inventaris semua objek di dalam arsip:
#!/bin/bash
# --list menampilkan daftar isi (TOC) archive custom.
# Baris komentar di atasnya memuat waktu pembuatan, kita buang;
# tiga angka di depan tiap baris (dump ID dan OID katalog) dipotong
# agar daftarnya ringkas dan stabil.
pg_restore --list backup_latihan.dump \
| grep -v '^;' \
| sed -E 's/^[0-9]+; [0-9]+ [0-9]+ //'Output yang Dihasilkan:
TABLE public pelanggan postgres
TABLE public pesanan postgres
TABLE public produk postgres
TABLE DATA public pelanggan postgres
TABLE DATA public pesanan postgres
TABLE DATA public produk postgres
CONSTRAINT public pelanggan pelanggan_pkey postgres
CONSTRAINT public pesanan pesanan_pkey postgres
CONSTRAINT public produk produk_pkey postgres
FK CONSTRAINT public pesanan pesanan_pelanggan_id_fkey postgres
FK CONSTRAINT public pesanan pesanan_produk_id_fkey postgresSebelas baris hasilnya adalah seluruh isi arsip: tiga TABLE (struktur), tiga TABLE DATA (isi baris), tiga CONSTRAINT (primary key), dan dua FK CONSTRAINT (foreign key pesanan). Dalam keluaran mentahnya setiap baris didahului tiga angka — nomor urut dump, OID katalog tipe objek, dan OID objek — plus blok komentar pembuka yang memuat waktu arsip dibuat; penyaringan di skrip membuang keduanya agar keluaran contoh ini stabil. Kegunaan praktisnya nyata: sebelum restore, --list menjawab “tabel apa saja sebenarnya ada di file ini?” — termasuk saat Anda mewarisi file dump berumur tiga tahun tanpa dokumentasi.
Restore Selektif dan Jebakan Constraint #
Skenario yang membuat pg_restore tak tergantikan: hanya satu tabel yang hilang atau rusak, dan Anda tidak ingin mengganggu sisanya. Opsi --table mengambil hanya objek yang namanya cocok:
#!/bin/bash
# Restore selektif: hanya tabel produk yang diambil dari archive.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS selektif_latihan WITH (FORCE)" \
-c "CREATE DATABASE selektif_latihan" > /dev/null
pg_restore -d selektif_latihan --table produk backup_latihan.dump
psql -X -d selektif_latihan -c "SELECT count(*) AS baris_produk FROM produk"
# Tabel lain tidak ikut ...
psql -X -d selektif_latihan -c "SELECT to_regclass('public.pesanan') IS NULL AS pesanan_tidak_ada"
# ... dan primary key produk juga tidak: --table mencocokkan nama objek saja.
psql -X -d selektif_latihan -c "SELECT to_regclass('public.produk_pkey') IS NULL AS pkey_tidak_ada"
# Resep yang membawa constraint: pulihkan skema penuh dulu ...
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS selektif_latihan WITH (FORCE)" \
-c "CREATE DATABASE selektif_latihan" > /dev/null
pg_restore --schema-only -d selektif_latihan backup_latihan.dump
# ... lalu isikan data hanya untuk tabel yang diinginkan.
pg_restore --data-only -d selektif_latihan --table produk backup_latihan.dump
psql -X -d selektif_latihan -c "SELECT to_regclass('public.produk_pkey') IS NOT NULL AS pkey_ada,
(SELECT count(*) FROM produk) AS baris_produk,
(SELECT count(*) FROM pesanan) AS baris_pesanan"Output yang Dihasilkan:
baris_produk
--------------
5
(1 row)
pesanan_tidak_ada
-------------------
t
(1 row)
pkey_tidak_ada
----------------
t
(1 row)
pkey_ada | baris_produk | baris_pesanan
----------+--------------+---------------
t | 5 | 0
(1 row)Bacaan hasilnya menegaskan dua fakta penting. Bagian pertama: --table produk membawa tabel produk lengkap dengan lima barisnya, tetapi pesanan_tidak_ada dan pkey_tidak_ada bernilai t — tabel lain tidak ikut, dan primary key-nya pun tidak. Penyaring --table mencocokkan nama objek satu per satu; constraint produk_pkey adalah objek tersendiri dengan nama yang berbeda, jadi tidak terpilih. Bagian kedua menunjukkan resep yang benar untuk kebutuhan “satu tabel beserta constraint-nya”: pulihkan seluruh skema dengan --schema-only (semua tabel dan constraint tercipta kosong), kemudian isikan data yang diinginkan saja dengan --data-only --table produk. Hasil akhirnya: pkey_ada bernilai t, produk berisi lima baris, pesanan hadir tapi kosong.
Tiga Opsi yang Sering Dibutuhkan #
Tiga varian pemulihan lain menutup kebutuhan sehari-hari — struktur tanpa data, restore menimpa, dan restore paralel — dalam satu skrip:
#!/bin/bash
# --schema-only: struktur lengkap tanpa satu baris data pun.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS variasi_latihan WITH (FORCE)" \
-c "CREATE DATABASE variasi_latihan" > /dev/null
pg_restore --schema-only -d variasi_latihan backup_latihan.dump
psql -X -d variasi_latihan -c "SELECT to_regclass('public.pesanan') IS NOT NULL AS tabel_ada,
(SELECT count(*) FROM pesanan) AS jumlah_baris"
# --clean --if-exists: pulihkan menimpa isi lama tanpa error duplikat.
psql -X -d variasi_latihan -v ON_ERROR_STOP=1 \
-c "INSERT INTO pelanggan VALUES (9, 'Pelanggan Baru', '[email protected]')" > /dev/null
pg_restore --clean --if-exists -d variasi_latihan backup_latihan.dump
psql -X -d variasi_latihan -c "SELECT count(*) AS baris_setelah_ditimpa FROM pelanggan"
# --jobs N: beberapa tabel dipulihkan sekaligus secara paralel.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS paralel_latihan WITH (FORCE)" \
-c "CREATE DATABASE paralel_latihan" > /dev/null
pg_restore -j 2 -d paralel_latihan backup_latihan.dump
psql -X -d paralel_latihan -c "SELECT (SELECT count(*) FROM produk) AS produk,
(SELECT count(*) FROM pelanggan) AS pelanggan,
(SELECT count(*) FROM pesanan) AS pesanan"Output yang Dihasilkan:
tabel_ada | jumlah_baris
-----------+--------------
t | 0
(1 row)
baris_setelah_ditimpa
-----------------------
3
(1 row)
produk | pelanggan | pesanan
--------+-----------+---------
5 | 3 | 4
(1 row)Tiga pengamatan dari keluarannya: --schema-only menghadirkan pesanan tetapi kosong (tabel_ada = t, jumlah_baris = 0) — cara cepat menduplikasi struktur ke database uji. --clean --if-exists menjatuhkan objek lama sebelum memulihkan yang baru — baris Pelanggan Baru yang disisipkan sebelumnya lenyap ditimpa isi arsip, dan jumlah pelanggan kembali ke 3; tanpa --if-exists, restore pertama ke database kosong akan error karena DROP objek yang belum ada. Terakhir, -j 2 memulihkan dengan dua proses data sekaligus — hasilnya identik dengan restore biasa (5 / 3 / 4), dan pada database besar dengan banyak tabel besar inilah opsi ini memangkas RTO secara nyata.
Ketika pg_restore Menolak: Format Plain #
Tutup chapter ini dengan percakapan singkat yang pasti Anda alami suatu hari nanti — menjamah file plain dengan pg_restore:
#!/bin/bash
# pg_restore hanya mengerti format custom dan directory.
# File teks hasil pg_dump polos ditolak mentah-mentah:
pg_dump "$PGDATABASE" > backup_plain.sql
pg_restore -d "$PGDATABASE" backup_plain.sql 2>&1 || echo "exit code: $?"Output yang Dihasilkan:
pg_restore: error: input file appears to be a text format dump. Please use psql.
exit code: 1Pesan input file appears to be a text format dump. Please use psql. dan exit code 1 adalah jawaban tegasnya — arsip dan teks adalah dua dunia berbeda, dan tabel di awal chapter adalah peta memutuskan alat mana yang berlaku. Pola 2>&1 || echo "exit code: $?" pada skrip juga patut dicatat: pg_restore menulis kesalahan ke stderr, diarahkan ke keluaran standar agar ikut terlihat, dan exit code-nya dicatat karena itulah sinyal yang diperiksa skrip otomatis Anda.
Dengan siklus backup-restore logis yang kini utuh dari pg_dump sampai verifikasi, satu keluarga strategi sudah tuntas. Namun untuk cluster besar dengan RTO yang ketat, memutar ulang SQL tetap lambat. Keluarga kedua menawarkan jalan lain: menyalin file data apa adanya — dan itu pekerjaan chapter Physical Backup
.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
backup_plain.sql
Unduh berkas--
-- PostgreSQL database dump
--
\restrict RthhasZFoVxLxL8D9ca29S9vKapDno5GShbRZU4yrrKdhlRL9KjGTqFLYSdTV8T
-- Dumped from database version 17.11 (Debian 17.11-0+deb13u1)
-- Dumped by pg_dump version 17.11 (Debian 17.11-0+deb13u1)
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET transaction_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: pelanggan; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.pelanggan (
id integer NOT NULL,
nama character varying(40),
email character varying(60)
);
ALTER TABLE public.pelanggan OWNER TO postgres;
--
-- Name: pesanan; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.pesanan (
id integer NOT NULL,
pelanggan_id integer,
produk_id integer,
qty integer
);
ALTER TABLE public.pesanan OWNER TO postgres;
--
-- Name: produk; Type: TABLE; Schema: public; Owner: postgres
--
CREATE TABLE public.produk (
id integer NOT NULL,
nama character varying(40),
harga numeric(10,2)
);
ALTER TABLE public.produk OWNER TO postgres;
--
-- Data for Name: pelanggan; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.pelanggan (id, nama, email) FROM stdin;
1 Budi Santoso budi@example.com
2 Siti Aminah siti@example.com
3 Rina Wijaya rina@example.com
\.
--
-- Data for Name: pesanan; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.pesanan (id, pelanggan_id, produk_id, qty) FROM stdin;
101 1 1 2
102 2 3 1
103 1 4 5
104 3 2 3
\.
--
-- Data for Name: produk; Type: TABLE DATA; Schema: public; Owner: postgres
--
COPY public.produk (id, nama, harga) FROM stdin;
1 Kopi Gayo 250g 45000.00
2 Teh Melati 100g 15000.00
3 Gula Aren 500g 32000.00
4 Beras Pandan 1kg 68000.00
5 Susu Kental 375g 21000.00
\.
--
-- Name: pelanggan pelanggan_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.pelanggan
ADD CONSTRAINT pelanggan_pkey PRIMARY KEY (id);
--
-- Name: pesanan pesanan_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.pesanan
ADD CONSTRAINT pesanan_pkey PRIMARY KEY (id);
--
-- Name: produk produk_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.produk
ADD CONSTRAINT produk_pkey PRIMARY KEY (id);
--
-- Name: pesanan pesanan_pelanggan_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.pesanan
ADD CONSTRAINT pesanan_pelanggan_id_fkey FOREIGN KEY (pelanggan_id) REFERENCES public.pelanggan(id);
--
-- Name: pesanan pesanan_produk_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
ALTER TABLE ONLY public.pesanan
ADD CONSTRAINT pesanan_produk_id_fkey FOREIGN KEY (produk_id) REFERENCES public.produk(id);
--
-- PostgreSQL database dump complete
--
\unrestrict RthhasZFoVxLxL8D9ca29S9vKapDno5GShbRZU4yrrKdhlRL9KjGTqFLYSdTV8T
lihat-isinya.sh
Unduh berkas#!/bin/bash
# --list menampilkan daftar isi (TOC) archive custom.
# Baris komentar di atasnya memuat waktu pembuatan, kita buang;
# tiga angka di depan tiap baris (dump ID dan OID katalog) dipotong
# agar daftarnya ringkas dan stabil.
pg_restore --list backup_latihan.dump \
| grep -v '^;' \
| sed -E 's/^[0-9]+; [0-9]+ [0-9]+ //'
plain-error.sh
Unduh berkas#!/bin/bash
# pg_restore hanya mengerti format custom dan directory.
# File teks hasil pg_dump polos ditolak mentah-mentah:
pg_dump "$PGDATABASE" > backup_plain.sql
pg_restore -d "$PGDATABASE" backup_plain.sql 2>&1 || echo "exit code: $?"
restore-selektif.sh
Unduh berkas#!/bin/bash
# Restore selektif: hanya tabel produk yang diambil dari archive.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS selektif_latihan WITH (FORCE)" \
-c "CREATE DATABASE selektif_latihan" > /dev/null
pg_restore -d selektif_latihan --table produk backup_latihan.dump
psql -X -d selektif_latihan -c "SELECT count(*) AS baris_produk FROM produk"
# Tabel lain tidak ikut ...
psql -X -d selektif_latihan -c "SELECT to_regclass('public.pesanan') IS NULL AS pesanan_tidak_ada"
# ... dan primary key produk juga tidak: --table mencocokkan nama objek saja.
psql -X -d selektif_latihan -c "SELECT to_regclass('public.produk_pkey') IS NULL AS pkey_tidak_ada"
# Resep yang membawa constraint: pulihkan skema penuh dulu ...
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS selektif_latihan WITH (FORCE)" \
-c "CREATE DATABASE selektif_latihan" > /dev/null
pg_restore --schema-only -d selektif_latihan backup_latihan.dump
# ... lalu isikan data hanya untuk tabel yang diinginkan.
pg_restore --data-only -d selektif_latihan --table produk backup_latihan.dump
psql -X -d selektif_latihan -c "SELECT to_regclass('public.produk_pkey') IS NOT NULL AS pkey_ada,
(SELECT count(*) FROM produk) AS baris_produk,
(SELECT count(*) FROM pesanan) AS baris_pesanan"
siapkan-sumber.sql
Unduh berkas-- Database sumber untuk siklus backup-restore: tiga tabel berelasi.
CREATE TABLE produk (
id integer PRIMARY KEY,
nama varchar(40),
harga numeric(10,2)
);
INSERT INTO produk (id, nama, harga) VALUES
(1, 'Kopi Gayo 250g', 45000),
(2, 'Teh Melati 100g', 15000),
(3, 'Gula Aren 500g', 32000),
(4, 'Beras Pandan 1kg', 68000),
(5, 'Susu Kental 375g', 21000);
CREATE TABLE pelanggan (
id integer PRIMARY KEY,
nama varchar(40),
email varchar(60)
);
INSERT INTO pelanggan (id, nama, email) VALUES
(1, 'Budi Santoso', '[email protected]'),
(2, 'Siti Aminah', '[email protected]'),
(3, 'Rina Wijaya', '[email protected]');
CREATE TABLE pesanan (
id integer PRIMARY KEY,
pelanggan_id integer REFERENCES pelanggan(id),
produk_id integer REFERENCES produk(id),
qty integer
);
INSERT INTO pesanan (id, pelanggan_id, produk_id, qty) VALUES
(101, 1, 1, 2),
(102, 2, 3, 1),
(103, 1, 4, 5),
(104, 3, 2, 3);
SELECT (SELECT count(*) FROM produk) AS jumlah_produk,
(SELECT count(*) FROM pelanggan) AS jumlah_pelanggan,
(SELECT count(*) FROM pesanan) AS jumlah_pesanan;
siklus-restore.sh
Unduh berkas#!/bin/bash
pg_isready -q || { echo "server tidak siap"; exit 1; }
# Tahap 1: cadangkan database sumber dalam format custom.
# (Ukuran berkas sengaja tidak ditampilkan: format custom menyisipkan
# stempel waktu pembuatan sehingga ukurannya berubah tiap eksekusi.)
pg_dump -Fc "$PGDATABASE" -f backup_latihan.dump
pg_restore --list backup_latihan.dump | grep -c 'TABLE DATA'
# Tahap 2: siapkan database tujuan yang kosong.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS pulih_latihan WITH (FORCE)" \
-c "CREATE DATABASE pulih_latihan" > /dev/null
# Tahap 3: pulihkan seluruh isi archive.
pg_restore -d pulih_latihan backup_latihan.dump
echo "exit pg_restore: $?"
# Tahap 4: verifikasi -- jumlah dan isi harus identik dengan sumbernya.
psql -X -d pulih_latihan -c "SELECT (SELECT count(*) FROM produk) AS produk,
(SELECT count(*) FROM pelanggan) AS pelanggan,
(SELECT count(*) FROM pesanan) AS pesanan"
psql -X -d pulih_latihan -c "SELECT ps.id, pl.nama AS pelanggan, pr.nama AS produk, ps.qty
FROM pesanan ps
JOIN pelanggan pl ON pl.id = ps.pelanggan_id
JOIN produk pr ON pr.id = ps.produk_id
ORDER BY ps.id"
variasi-restore.sh
Unduh berkas#!/bin/bash
# --schema-only: struktur lengkap tanpa satu baris data pun.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS variasi_latihan WITH (FORCE)" \
-c "CREATE DATABASE variasi_latihan" > /dev/null
pg_restore --schema-only -d variasi_latihan backup_latihan.dump
psql -X -d variasi_latihan -c "SELECT to_regclass('public.pesanan') IS NOT NULL AS tabel_ada,
(SELECT count(*) FROM pesanan) AS jumlah_baris"
# --clean --if-exists: pulihkan menimpa isi lama tanpa error duplikat.
psql -X -d variasi_latihan -v ON_ERROR_STOP=1 \
-c "INSERT INTO pelanggan VALUES (9, 'Pelanggan Baru', '[email protected]')" > /dev/null
pg_restore --clean --if-exists -d variasi_latihan backup_latihan.dump
psql -X -d variasi_latihan -c "SELECT count(*) AS baris_setelah_ditimpa FROM pelanggan"
# --jobs N: beberapa tabel dipulihkan sekaligus secara paralel.
psql -X -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS paralel_latihan WITH (FORCE)" \
-c "CREATE DATABASE paralel_latihan" > /dev/null
pg_restore -j 2 -d paralel_latihan backup_latihan.dump
psql -X -d paralel_latihan -c "SELECT (SELECT count(*) FROM produk) AS produk,
(SELECT count(*) FROM pelanggan) AS pelanggan,
(SELECT count(*) FROM pesanan) AS pesanan"