Postgres: xóa toàn bộ cơ sở dữ liệu trước khi tạo lại / điền lại từ tập lệnh bash


139

Tôi đang viết một kịch bản shell (sẽ trở thành một cronjob) sẽ:

1: kết xuất cơ sở dữ liệu sản xuất của tôi

2: nhập kết xuất vào cơ sở dữ liệu phát triển của tôi

Giữa bước 1 và 2, tôi cần xóa cơ sở dữ liệu phát triển (bỏ tất cả các bảng?). Làm thế nào là điều này được thực hiện tốt nhất từ ​​một kịch bản shell? Cho đến nay, nó trông như thế này:

#!/bin/bash
time=`date '+%Y'-'%m'-'%d'`
# 1. export(dump) the current production database
pg_dump -U production_db_name > /backup/dir/backup-${time}.sql

# missing step: drop all tables from development database so it can be re-populated

# 2. load the backup into the development database
psql -U development_db_name < backup/dir/backup-${time}.sql

3
oneliner cho những người vội vã:dbname='db_name' && dropdb $dbname && createdb $dbname && psql -d $dbname -f dump.sql
ruuter

oneliner này yêu cầu bạn phải có quyền để tạo / xóa cơ sở dữ liệu. Cách tiếp cận mà tác giả đang cố gắng không yêu cầu đặc quyền.
ribamar

Câu trả lời:


188

Tôi chỉ cần bỏ cơ sở dữ liệu và sau đó tạo lại nó. Trên hệ thống UNIX hoặc Linux, cần thực hiện:

$ dropdb development_db_name
$ createdb developmnent_db_name

Đó là cách tôi làm điều đó, thực sự.


Đây là cách tôi làm điều đó là tốt. Sau đó, chỉ cần khôi phục vào db vừa tạo.
Arthur Thomas

3
Vâng. điều này tốt hơn bởi vì có thể có những đối tượng không phải là một phần của bãi rác mà bạn đang khôi phục. trong trường hợp này chắc chắn họ sẽ bị giết.
pstanton

7
Một mẹo giúp tôi tiết kiệm thời gian là $ sudo -u postgres dropdb DATABASE_NAME
Alvin

36
Nhưng ... còn quyền và cơ sở dữ liệu thì sao?
Emanuele Paolini

6
@EmanuelePaolini createdb --owner=db_owner [--template=template0 --encoding=UTF8] db_nametôi mặc định thêm hai cái cuối cùng vào tất cả các cơ sở dữ liệu
mcalex

91

Nếu bạn thực sự không cần một bản sao lưu cơ sở dữ liệu được đổ vào đĩa ở định dạng tệp tập lệnh .sql văn bản đơn giản, bạn có thể kết nối pg_dumppg_restoretrực tiếp với nhau qua một đường ống.

Để thả và tạo lại các bảng, bạn có thể sử dụng --cleantùy chọn dòng lệnh pg_dumpđể phát ra các lệnh SQL để xóa (thả) các đối tượng cơ sở dữ liệu trước (các lệnh cho) tạo chúng. (Điều này sẽ không bỏ toàn bộ cơ sở dữ liệu, chỉ mỗi bảng / trình tự / chỉ mục / v.v. trước khi tạo lại chúng.)

Hai cái trên sẽ trông giống như thế này:

pg_dump -U username --clean | pg_restore -U username

1
Tôi thích giải pháp này, vì tôi muốn có một bản sao lưu, bây giờ tôi đang làm điều này: pg_dump -Ft -U sản xuất_db_name> /backup/dir/backup-$ nbtime -clean /backup/dir/backup-$ nbtime Bolog.tar hoạt động như một cơ duyên, cảm ơn sự giúp đỡ của bạn!
Hoff

38
Coi chừng: tùy chọn --clean chỉ xóa những quan hệ được tìm thấy trong tệp khôi phục. Điều này có nghĩa là nếu bạn thêm một bảng để thử nghiệm, sau đó muốn xóa nó (để đồng bộ hóa với DB sản xuất chẳng hạn), nó sẽ không bị xóa.
ianaré

6
Điều quan trọng là phải nhớ rằng tùy chọn --clean của pg_dump chỉ hoạt động với các bản sao lưu văn bản đơn giản. Vì tài liệu nêu rõ ở đây postgresql.org/docs/9.4/static/app-pgdump.html , bạn cần sử dụng --clean trên pg_restore để sao lưu lưu trữ.
Kikin-Sama

6
Có cách nào để đưa tầng trong tùy chọn "--clean" không. Vì nó là tùy chọn này trông vô dụng. Tôi nhận được "LRI: không thể loại bỏ lược đồ công khai vì các đối tượng khác phụ thuộc vào nó" giống như 100% thời gian sử dụng nó.
dùng4674453

Câu hỏi hỏi về việc loại bỏ tất cả các bảng. Điều này chỉ loại bỏ các bảng được tìm thấy trong cơ sở dữ liệu mà pg_dump đang bán phá giá.
jbg

13

Mặc dù dòng sau đây được lấy từ tập lệnh bó cửa sổ, lệnh sẽ khá giống nhau:

psql -U username -h localhost -d postgres -c "DROP DATABASE \"$DATABASE\";"

Lệnh này được sử dụng để xóa toàn bộ cơ sở dữ liệu, bằng cách thực sự loại bỏ nó. Các $DATABASE(trong Windows nên %DATABASE%) trong lệnh là một biến môi trường cửa sổ phong cách mà đánh giá lại để tên cơ sở dữ liệu. Bạn sẽ cần phải thay thế bằng của bạn development_db_name.


4
thì tại sao không sử dụng đã có sẵn dropdbcreatedblệnh? Nếu bạn có thể chạy psql, bạn cũng có thể chạy chúng.
Mike 'Pomax' Kamermans

10

Để đổ:

pg_dump -Fc mydb > db.dump

Để khôi phục lại:

pg_restore --verbose --clean --no-acl --no-owner -h localhost -U myuser -d my_db db/latest.dump

7

Nếu bạn muốn dọn dẹp cơ sở dữ liệu của mình có tên "example_db":

1) Đăng nhập vào một db khác (ví dụ 'postgres'):

psql postgres

2) Xóa cơ sở dữ liệu của bạn:

DROP DATABASE example_db;

3) Tái tạo cơ sở dữ liệu của bạn:

CREATE DATABASE example_db;


4

Lưu ý: câu trả lời của tôi là về việc thực sự xóa các bảng và các đối tượng cơ sở dữ liệu khác; để xóa tất cả dữ liệu trong các bảng, tức là cắt bớt tất cả các bảng , Endre Cả hai đã cung cấp một câu lệnh (thực thi trực tiếp) được thực hiện tốt tương tự một tháng sau đó.

Đối với các trường hợp bạn không thể DROP SCHEMA public CASCADE;, DROP OWNED BY current_user;hoặc một cái gì đó, đây là tập lệnh SQL độc lập mà tôi đã viết, nó an toàn cho giao dịch (nghĩa là bạn có thể đặt nó ở giữa BEGIN;ROLLBACK;để kiểm tra hoặc COMMIT;thực hiện hành động đó) và thực sự làm việc đó) và Dọn dẹp tất cả các đối tượng cơ sở dữ liệu của thành phố tốt, tất cả những thứ được sử dụng trong cơ sở dữ liệu mà ứng dụng của chúng tôi sử dụng hoặc tôi có thể thêm vào một cách hợp lý, đó là:

  • kích hoạt trên bàn
  • các ràng buộc trên các bảng (FK, PK CHECK,, UNIQUE)
  • chỉ dẫn
  • VIEWs (bình thường hoặc vật chất hóa)
  • những cái bàn
  • trình tự
  • thói quen (tổng hợp chức năng, chức năng, thủ tục)
  • tất cả các schemata mặc định (tức là không publichoặc DB-Internal), chúng tôi sở hữu: kịch bản này rất hữu ích khi được chạy dưới dạng không phải là một siêu người dùng cơ sở dữ liệu. một siêu người dùng có thể loại bỏ tất cả các schemata (mặc dù những cái thực sự quan trọng vẫn bị loại trừ rõ ràng)
  • tiện ích mở rộng (do người dùng đóng góp nhưng tôi thường cố tình để chúng trong)

Không bị rơi là (một số cố ý; một số chỉ vì tôi không có ví dụ trong DB của chúng tôi):

  • các publicgiản đồ (ví dụ như cho các công cụ mở rộng-cung cấp trong họ)
  • collations và các công cụ địa phương khác
  • kích hoạt sự kiện
  • văn bản tìm kiếm công cụ, ... (xem ở đây cho các công cụ khác mà tôi có thể đã bỏ lỡ)
  • vai trò hoặc cài đặt bảo mật khác
  • loại hỗn hợp
  • bàn nướng bánh mì
  • Bảng FDW và nước ngoài

Điều này thực sự hữu ích cho các trường hợp khi kết xuất mà bạn muốn khôi phục thuộc phiên bản lược đồ cơ sở dữ liệu khác (ví dụ với Debian dbconfig-common, Flyway hoặc Liquibase / DB-Manul) so với cơ sở dữ liệu bạn muốn khôi phục.

Tôi cũng đã có một phiên bản xóa tất cả mọi thứ ngoại trừ hai bảng và những gì thuộc về họ (một chuỗi, được kiểm tra thủ công, xin lỗi, tôi biết, nhàm chán) trong trường hợp ai đó quan tâm; khác biệt là nhỏ. Liên hệ với tôi hoặc kiểm tra repo này nếu quan tâm.

SQL

-- Copyright © 2019, 2020
--      mirabilos <t.glaser@tarent.de>
--
-- Provided that these terms and disclaimer and all copyright notices
-- are retained or reproduced in an accompanying document, permission
-- is granted to deal in this work without restriction, including un‐
-- limited rights to use, publicly perform, distribute, sell, modify,
-- merge, give away, or sublicence.
--
-- This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
-- the utmost extent permitted by applicable law, neither express nor
-- implied; without malicious intent or gross negligence. In no event
-- may a licensor, author or contributor be held liable for indirect,
-- direct, other damage, loss, or other issues arising in any way out
-- of dealing in the work, even if advised of the possibility of such
-- damage or existence of a defect, except proven that it results out
-- of said person’s immediate fault when using the work as intended.
-- -
-- Drop everything from the PostgreSQL database.

DO $$
DECLARE
        q TEXT;
        r RECORD;
BEGIN
        -- triggers
        FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
                FROM pg_catalog.pg_trigger pt, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pt.tgrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pt.tgisinternal=false
            ) LOOP
                EXECUTE format('DROP TRIGGER %I ON %I.%I;',
                    r.tgname, r.nspname, r.relname);
        END LOOP;
        -- constraints #1: foreign key
        FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
                FROM pg_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pcon.contype='f'
            ) LOOP
                EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
                    r.nspname, r.relname, r.conname);
        END LOOP;
        -- constraints #2: the rest
        FOR r IN (SELECT pns.nspname, pc.relname, pcon.conname
                FROM pg_catalog.pg_constraint pcon, pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace AND pc.oid=pcon.conrelid
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pcon.contype<>'f'
            ) LOOP
                EXECUTE format('ALTER TABLE ONLY %I.%I DROP CONSTRAINT %I;',
                    r.nspname, r.relname, r.conname);
        END LOOP;
        -- indicēs
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='i'
            ) LOOP
                EXECUTE format('DROP INDEX %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- normal and materialised views
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind IN ('v', 'm')
            ) LOOP
                EXECUTE format('DROP VIEW %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- tables
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='r'
            ) LOOP
                EXECUTE format('DROP TABLE %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- sequences
        FOR r IN (SELECT pns.nspname, pc.relname
                FROM pg_catalog.pg_class pc, pg_catalog.pg_namespace pns
                WHERE pns.oid=pc.relnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pc.relkind='S'
            ) LOOP
                EXECUTE format('DROP SEQUENCE %I.%I;',
                    r.nspname, r.relname);
        END LOOP;
        -- extensions (only if necessary; keep them normally)
        FOR r IN (SELECT pns.nspname, pe.extname
                FROM pg_catalog.pg_extension pe, pg_catalog.pg_namespace pns
                WHERE pns.oid=pe.extnamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
            ) LOOP
                EXECUTE format('DROP EXTENSION %I;', r.extname);
        END LOOP;
        -- aggregate functions first (because they depend on other functions)
        FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
                FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns, pg_catalog.pg_aggregate pagg
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
                    AND pagg.aggfnoid=pp.oid
            ) LOOP
                EXECUTE format('DROP AGGREGATE %I.%I(%s);',
                    r.nspname, r.proname,
                    pg_get_function_identity_arguments(r.oid));
        END LOOP;
        -- routines (functions, aggregate functions, procedures, window functions)
        IF EXISTS (SELECT * FROM pg_catalog.pg_attribute
                WHERE attrelid='pg_catalog.pg_proc'::regclass
                    AND attname='prokind' -- PostgreSQL 11+
            ) THEN
                q := 'CASE pp.prokind
                        WHEN ''p'' THEN ''PROCEDURE''
                        WHEN ''a'' THEN ''AGGREGATE''
                        ELSE ''FUNCTION''
                    END';
        ELSIF EXISTS (SELECT * FROM pg_catalog.pg_attribute
                WHERE attrelid='pg_catalog.pg_proc'::regclass
                    AND attname='proisagg' -- PostgreSQL ≤10
            ) THEN
                q := 'CASE pp.proisagg
                        WHEN true THEN ''AGGREGATE''
                        ELSE ''FUNCTION''
                    END';
        ELSE
                q := '''FUNCTION''';
        END IF;
        FOR r IN EXECUTE 'SELECT pns.nspname, pp.proname, pp.oid, ' || q || ' AS pt
                FROM pg_catalog.pg_proc pp, pg_catalog.pg_namespace pns
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN (''information_schema'', ''pg_catalog'', ''pg_toast'')
            ' LOOP
                EXECUTE format('DROP %s %I.%I(%s);', r.pt,
                    r.nspname, r.proname,
                    pg_get_function_identity_arguments(r.oid));
        END LOOP;
        -- nōn-default schemata we own; assume to be run by a not-superuser
        FOR r IN (SELECT pns.nspname
                FROM pg_catalog.pg_namespace pns, pg_catalog.pg_roles pr
                WHERE pr.oid=pns.nspowner
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast', 'public')
                    AND pr.rolname=current_user
            ) LOOP
                EXECUTE format('DROP SCHEMA %I;', r.nspname);
        END LOOP;
        -- voilà
        RAISE NOTICE 'Database cleared!';
END; $$;

Đã thử nghiệm, ngoại trừ các bổ sung sau này (được extensionsđóng góp bởi Clément Prévost ), trên PostgreQuery 9.6 ( jessie-backports). Loại bỏ tổng hợp được thử nghiệm vào ngày 9.6 và 12.2, loại bỏ quy trình cũng được thử nghiệm vào ngày 12.2. Sửa lỗi và cải tiến hơn nữa chào mừng!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.