web-dev-qa-db-fra.com

Copier une table (y compris les index) en postgres

J'ai une table postgres. Je dois en supprimer certaines données. J'allais créer une table temporaire, copier les données, recréer les index et supprimer les lignes dont j'avais besoin. Je ne peux pas supprimer des données de la table d'origine, car cette table d'origine est la source des données. Dans un cas, j'ai besoin d'obtenir des résultats qui dépendent de la suppression de X, dans un autre cas, je devrai supprimer Y. J'ai donc besoin de toutes les données d'origine pour qu'elles soient toujours disponibles et disponibles.

Cependant, il semble un peu idiot de recréer la table, de la recopier et de recréer les index. Y a-t-il de toute façon dans postgres pour lui dire "Je veux une copie séparée complète de ce tableau, y compris la structure, les données et les index"?

Malheureusement, PostgreSQL n'a pas de "CREATE TABLE .. LIKE X INCLUDING INDEXES"

80
Rory

Le nouveau PostgreSQL (depuis 8.3 selon les documents) peut utiliser "INCLUS LES INDEX":

# select version();
                                             version
-------------------------------------------------------------------------------------------------
 PostgreSQL 8.3.7 on x86_64-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.4 (Ubuntu 4.2.4-1ubuntu3)
(1 row)

Comme vous pouvez le voir, je teste la 8.3.

Maintenant, créons une table:

# create table x1 (id serial primary key, x text unique);
NOTICE:  CREATE TABLE will create implicit sequence "x1_id_seq" for serial column "x1.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x1_pkey" for table "x1"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x1_x_key" for table "x1"
CREATE TABLE

Et voyez à quoi ça ressemble:

# \d x1
                         Table "public.x1"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x1_pkey" PRIMARY KEY, btree (id)
    "x1_x_key" UNIQUE, btree (x)

Maintenant, nous pouvons copier la structure:

# create table x2 ( like x1 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "x2_pkey" for table "x2"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "x2_x_key" for table "x2"
CREATE TABLE

Et vérifiez la structure:

# \d x2
                         Table "public.x2"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x2_pkey" PRIMARY KEY, btree (id)
    "x2_x_key" UNIQUE, btree (x)

Si vous utilisez PostgreSQL pré-8.3, vous pouvez simplement utiliser pg_dump avec l'option "-t" pour spécifier 1 table, changer le nom de la table dans le vidage et le charger à nouveau:

=> pg_dump -t x2 | sed 's/x2/x3/g' | psql
SET
SET
SET
SET
SET
SET
SET
SET
CREATE TABLE
ALTER TABLE
ALTER TABLE
ALTER TABLE

Et maintenant le tableau est:

# \d x3
                         Table "public.x3"
 Column |  Type   |                    Modifiers
--------+---------+-------------------------------------------------
 id     | integer | not null default nextval('x1_id_seq'::regclass)
 x      | text    |
Indexes:
    "x3_pkey" PRIMARY KEY, btree (id)
    "x3_x_key" UNIQUE, btree (x)
102
user80168
[CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name
    [ (column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
    [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
    [ TABLESPACE tablespace ]
    AS query][1]  

Voici un exemple

CREATE TABLE films_recent AS
  SELECT * FROM films WHERE date_prod >= '2002-01-01';

L'autre façon de créer une nouvelle table à partir de la première consiste à utiliser

    CREATE TABLE films_recent (LIKE films INCLUDING INDEXES);  

    INSERT INTO films_recent
         SELECT *
           FROM books
          WHERE date_prod >= '2002-01-01';  

Notez que Postgresql a un patch out pour résoudre les problèmes d'espace de table si la deuxième méthode est utilisée

42
WolfmanDragon

J'ai une table postgres. Je dois en supprimer certaines données.

Je suppose que ...

delete from yourtable
where <condition(s)>

... ne fonctionnera pas pour une raison quelconque. (Voulez-vous partager cette raison?)

J'allais créer une table temporaire, copier les données, recréer les index et supprimer les lignes dont j'avais besoin.

Regardez dans pg_dump et pg_restore. Utiliser pg_dump avec quelques options intelligentes et peut-être éditer la sortie avant pg_restoring pourrait faire l'affaire.


Étant donné que vous effectuez une analyse de type "et si" sur les données, je me demande si vous pourriez être mieux en utilisant des vues.

Vous pouvez définir une vue pour chaque scénario que vous souhaitez tester en fonction de la négation de ce que vous souhaitez exclure. C'est-à-dire, définissez une vue en fonction de ce que vous souhaitez inclure. Par exemple, si vous voulez une "fenêtre" sur les données où vous avez "supprimé" les lignes où X = Y, alors vous créeriez une vue sous forme de lignes où (X! = Y).

Les vues sont stockées dans la base de données (dans le catalogue système) en tant que requête de définition. Chaque fois que vous interrogez la vue, le serveur de base de données recherche la requête sous-jacente qui la définit et l'exécute (ET avec toutes les autres conditions que vous avez utilisées). Cette approche présente plusieurs avantages:

  1. Vous ne dupliquez jamais aucune partie de vos données.
  2. Les index déjà utilisés pour la table de base (votre table "réelle" d'origine) seront utilisés (comme jugé approprié par l'optimiseur de requête) lorsque vous interrogerez chaque vue/scénario. Il n'est pas nécessaire de les redéfinir ou de les copier.
  3. Puisqu'une vue est une "fenêtre" (PAS un cliché) sur les "vraies" données dans la table de base, vous pouvez ajouter/mettre à jour/supprimer sur votre table de base et simplement réinterroger les scénarios de vue sans avoir besoin de recréer quoi que ce soit comme les données changent avec le temps.

Il y a bien sûr un compromis. Puisqu'une vue est une table virtuelle et non une "vraie" table (de base), vous exécutez en fait une requête (peut-être complexe) chaque fois que vous y accédez. Cela peut ralentir un peu les choses. Mais ce n'est peut-être pas le cas. Cela dépend de nombreux problèmes (taille et nature des données, qualité des statistiques dans le catalogue système, vitesse du matériel, charge d'utilisation, etc.). Vous ne saurez pas avant de l'essayer. Si (et seulement si) vous constatez réellement que les performances sont trop faibles, alors vous pourriez envisager d'autres options. (Vues matérialisées, copies de tableaux, ... tout ce qui échange de l'espace contre du temps.)

4
Alan

Créez une nouvelle table en utilisant une sélection pour saisir les données souhaitées. Échangez ensuite l'ancienne table avec la nouvelle.

create table mynewone as select * from myoldone where ...
mess (re-create) with indexes after the table swap.
1
jim

Un moyen simple est de tout inclure:

CREATE TABLE new_table (LIKE original_table INCLUDING ALL);
0
Ringtail