pg_restore: [pengarsip (db)] tidak dapat mengeksekusi query: ERROR: skema "public" sudah ada

Saya menggunakan pg_dump / pg_restore untuk mencadangkan dan memulihkan basis data PostgreSQL, tetapi saya mendapatkan beberapa pesan kesalahan (dan status keluar bukan nol) dari pg_restore. Saya mencoba kasus dasar yang sangat sederhana (diuraikan di bawah ini) tetapi masih mendapatkan kesalahan ini:

pg_restore: [archiver (db)] Kesalahan saat MEMPROCESSING TOC:
pg_restore: [archiver (db)] Kesalahan dari entri TOC 5; 2615 2200 SCHEMA public postgres
pg_restore: [archiver (db)] tidak dapat mengeksekusi query: ERROR: skema "public" sudah ada
    Perintahnya adalah: CREATE SCHEMA public;

Langkah-langkah untuk mereproduksi:

  1. Instal distro Ubuntu 14.04 vanilla yang baru (saya menggunakan Vagrant dengan kotak Vagrant ini).

  2. Instal PostgreSQL 9.3, konfigurasikan untuk mengizinkan koneksi lokal sebagai pengguna PostgreSQL "postgres &" dari pengguna Linux mana pun.

  3. Buatlah sebuah test database. Saya baru saja melakukannya:

    vagrant@vagrant-ubuntu-trusty-64:~$ psql --username=postgres postgres
    psql (9.3.5)
    Ketik "help" untuk bantuan.
    

    postgres=# create database mydb; MEMBUAT BASIS DATA postgres=# \q vagrant@vagrant-ubuntu-trusty-64:~$ psql --username=postgres mydb psql (9.3.5) Ketik "help" untuk bantuan.

    mydb=# membuat tabel data(entri bigint); CREATE TABLE mydb=# masukkan ke dalam data values(1); INSERT 0 1 mydb=# masukkan ke dalam data values(2); INSERT 0 1 mydb=# masukkan ke dalam data values(3); INSERT 0 1 mydb=# \q

  4. Buat backup database seperti ini:

    PGPASSWORD="postgres" pg_dump --dbname=mydb --username=postgres --format=custom > pg_backup.dump
  5. Hapus beberapa baris dari tabel data di mydb sehingga kita akan dapat mengetahui apakah kita berhasil memulihkan data.

  6. Kembalikan database dengan:

    PGPASSWORD="postgres" pg_restore --clean --create --dbname=postgres --username=postgres pg_backup.dump

Data dipulihkan, tetapi perintah pg_restore pada langkah 6 keluar dengan status 1 dan menunjukkan output berikut:

pg_restore: [archiver (db)] Kesalahan saat MEMPROCESSING TOC:
pg_restore: [archiver (db)] Kesalahan dari entri TOC 5; 2615 2200 SCHEMA public postgres
pg_restore: [archiver (db)] tidak dapat mengeksekusi query: ERROR: skema "public" sudah ada
    Perintahnya adalah: CREATE SCHEMA public;

PERINGATAN: kesalahan diabaikan saat pemulihan: 1

Saya tidak bisa mengabaikan ini karena saya menjalankan perintah ini secara terprogram dan perlu menggunakan status keluar untuk menentukan apakah restore gagal atau tidak. Awalnya, saya bertanya-tanya apakah masalah ini disebabkan karena saya meletakkan database saya di public (skema default). Saya beralasan bahwa publik akan dibuat sebagai hasil dari opsi --create oleh pg_restore sebelum data direstore (yang bisa dibayangkan akan mencoba membuat skema itu juga karena di situlah tabel saya berada), tetapi ketika saya mencoba langkah-langkah di atas dengan tabel saya dalam skema yang berbeda, hasilnya sama dan pesan errornya identik.

Apakah saya melakukan sesuatu yang salah? Mengapa saya melihat kesalahan ini?

Larutan

Kesalahan ini tidak berbahaya tetapi untuk menghilangkannya, saya pikir Anda perlu memecah pemulihan ini menjadi dua perintah, seperti pada:

dropdb -U postgres mydb && \
 pg_restore --create --dbname=postgres --username=postgres pg_backup.dump

Opsi -bersih di pg_restore tidak terlihat banyak tetapi sebenarnya menimbulkan masalah yang tidak sepele.

Untuk versi hingga 9.1

Kombinasi opsi --create dan --clean di pg_restore dulu merupakan kesalahan di versi PG yang lebih lama (hingga 9.1). Memang ada beberapa kontradiksi antara (mengutip manpage 9.1):

--bersih Membersihkan (drop) objek database sebelum membuatnya kembali

dan

--create Membuat database sebelum memulihkannya.

Karena apa gunanya membersihkan di dalam database baru?

Mulai dari versi 9.2

Kombinasi ini sekarang diterima dan dokumen mengatakan ini (mengutip manpage 9.3):

--bersih Bersihkan (drop) objek database sebelum membuatnya kembali. (Ini mungkin menghasilkan beberapa pesan kesalahan yang tidak berbahaya, jika ada objek yang tidak ada di database tujuan).

--create Membuat database sebelum memulihkannya. Jika --clean juga ditentukan, jatuhkan dan buat ulang database target sebelum menghubungkannya.

Sekarang dengan memiliki keduanya bersama-sama akan menghasilkan urutan seperti ini selama pemulihan Anda:

DROP DATABASE mydb;
...
CREATE DATABASE mydb WITH TEMPLATE = template0... [other options]
...
CREATE SCHEMA public;
...
CREATE TABLE...

Tidak ada DROP untuk setiap objek individu, hanya DROP DATABASE di awal. Jika tidak menggunakan --create ini akan menjadi kebalikannya.

Bagaimanapun juga urutan ini menimbulkan kesalahan skema public sudah ada karena membuat mydb dari template0 telah mengimpornya (yang mana ini normal, ini adalah inti dari database template).

Saya tidak yakin mengapa kasus ini tidak ditangani secara otomatis oleh pg_restore. Mungkin hal ini akan menyebabkan efek samping yang tidak diinginkan ketika admin memutuskan untuk mengkustomisasi template0 dan/atau mengubah tujuan public, bahkan jika kita tidak seharusnya melakukan itu.

Komentar (1)

Dalam kasus saya, alasannya adalah saya menggunakan pg_restore dari postgresql-contrib versi 11.2 untuk mengembalikan dump yang dibuat oleh pg_dump 9.6 ke klaster PostgreSQL 9.6.

Setelah saya menurunkan pg_restore saya kembali ke 9.6, kesalahan schema "public" already exists ini hilang, dan proses pemulihan bekerja seperti sebelumnya.

Komentar (1)