web-dev-qa-db-fra.com

Postgres: efface toute la base de données avant de recréer / re-remplir à partir d'un script bash

J'écris un script Shell (qui deviendra un travail cronjob) qui:

1: vider ma base de données de production

2: importer le dump dans ma base de développement

Entre les étapes 1 et 2, je dois effacer la base de développement (supprimer toutes les tables?). Comment cela est-il mieux réalisé à partir d'un script Shell? Jusqu'ici, cela ressemble à ceci:

#!/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
108
Hoff

Je laisserais simplement tomber la base de données et ensuite la recréer. Sur un système UNIX ou Linux, cela devrait le faire:

$ dropdb development_db_name
$ createdb developmnent_db_name

C'est comme ça que je le fais, en fait.

161
Haes

Si vous n'avez pas réellement besoin d'une sauvegarde de la base de données vidée sur le disque dans un format de fichier de script .sql en texte brut, vous pouvez vous connecter pg_dump et pg_restore directement ensemble sur un tuyau.

Pour supprimer et recréer des tables, vous pouvez utiliser le --clean option de ligne de commande pour pg_dump pour émettre des commandes SQL permettant de supprimer (supprimer) les objets de la base de données avant leur création. (Cela ne supprimera pas toute la base de données, mais seulement chaque table/séquence/index/etc. avant de les recréer.)

Les deux ci-dessus ressemblent à ceci:

pg_dump -U username --clean | pg_restore -U username
84
Bandi-T

Bien que la ligne suivante soit extraite d'un script batch Windows, la commande doit être assez similaire:

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

Cette commande est utilisée pour effacer toute la base de données, en la supprimant réellement. Le $DATABASE _ (sous Windows devrait être %DATABASE%) dans la commande est une variable d’environnement de style Windows qui correspond au nom de la base de données. Vous devrez le remplacer par votre development_db_name.

13
Frank Bollack

Jeter:

pg_dump -Fc mydb > db.dump

Restaurer:

pg_restore --verbose --clean --no-acl --no-owner -h localhost -U myuser -d my_db db/latest.dump
7
Carlos Júlio

J'ai utilisé:

pg_restore -c -d database_name filename.dump
6
Troy

Pour les cas où vous ne pouvez pas simplement DROP SCHEMA public CASCADE;, DROP OWNED BY current_user; Ou quelque chose du genre, voici un script SQL autonome que j'ai écrit et qui est sécurisé pour les transactions (c'est-à-dire que vous pouvez le placer entre BEGIN; Et soit ROLLBACK; Pour le tester ou COMMIT; Pour accomplir l'acte) et nettoie "tous" les objets de la base de données… eh bien, tous ceux utilisés dans la base de données que notre application utilise ou Je pourrais raisonnablement ajouter:

  • déclencheurs sur les tables
  • contraintes sur les tables (FK, PK, CHECK, UNIQUE)
  • indices
  • VIEWs (normal ou matérialisé)
  • les tables
  • des séquences
  • fonctions/procédures ( pg_proc.proisagg probablement devrait être respecté bien)
  • tous les schémas nōn-default (c'est-à-dire non public ou internes à la base de données) "nous" possèdent: le script est utile lorsqu'il est exécuté en tant que "non superutilisateur de base de données"; un super-utilisateur peut supprimer tous schemata (les plus importants sont toujours explicitement exclus)

Ne sont pas omis (certains délibérés; d'autres uniquement parce que je n'avais aucun exemple dans notre base de données):

  • le schéma public (par exemple pour les éléments fournis par leur extension)
  • des extensions
  • fonctions agrégées
  • des collations et autres objets locaux
  • déclencheurs d'événements
  • recherche de texte,… (voir ici pour d'autres choses que j'ai peut-être manquées)
  • rôles ou autres paramètres de sécurité
  • types composites
  • tables de pain grillé
  • FDW et tables étrangères

J'ai également une version qui supprime "tout sauf deux tables et ce qui leur appartient" au cas où quelqu'un serait intéressé; le diff est petit. Contactez moi si nécessaire.

Ceci est vraiment utile dans les cas où le cliché que vous souhaitez restaurer est d'une autre version du schéma de base de données (par exemple, avec Debian dbconfig-common, Flyway ou Liquibase/DB-Manul) que la base de données dans laquelle vous souhaitez la restaurer.

SQL

-- Copyright © 2019
--      mirabilos <[email protected]>
--
-- 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
        r RECORD;
BEGIN
        -- triggers
        FOR r IN (SELECT pns.nspname, pc.relname, pt.tgname
                FROM pg_trigger pt, pg_class pc, 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_constraint pcon, pg_class pc, 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_constraint pcon, pg_class pc, 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_class pc, 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_class pc, 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_class pc, 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_class pc, 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;
        -- functions / procedures
        FOR r IN (SELECT pns.nspname, pp.proname, pp.oid
                FROM pg_proc pp, pg_namespace pns
                WHERE pns.oid=pp.pronamespace
                    AND pns.nspname NOT IN ('information_schema', 'pg_catalog', 'pg_toast')
            ) LOOP
                EXECUTE format('DROP FUNCTION %I.%I(%s);',
                    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_namespace pns, 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; $$;

Testé sur PostgreSQL 9.6 (jessie-backports). Les corrections de bogues et autres améliorations sont les bienvenues!

2
mirabilos

Si vous souhaitez nettoyer votre base de données nommée "example_db":

1) Connectez-vous à une autre base de données (par exemple, 'postgres'):

psql postgres

2) Supprimer votre base de données:

DROP DATABASE example_db;

3) Recréez votre base de données:

CREATE DATABASE example_db;
1
Kamil Siwek