Le moyen le plus efficace d'ajouter une colonne série à une énorme table

10

Quel est le moyen le plus rapide d'ajouter une colonne BIGSERIAL à une immense table (~ 3 lignes bil., ~ 174 Go)?

ÉDITER:

  • Je veux que la colonne soit des valeurs incrémentées pour les lignes existantes ( NOT NULL).
  • Je n'ai pas défini de facteur de remplissage (ce qui ressemble rétrospectivement à une mauvaise décision).
  • Je n'ai pas de problème avec l'espace disque, je veux juste que ce soit aussi rapide que possible.
Thi Duong Nguyen
la source

Réponses:

12

Quel est le problème avec:

ALTER TABLE foo ADD column bar bigserial;

Sera automatiquement rempli de valeurs uniques (commençant par 1).

Si vous souhaitez un numéro pour chaque ligne existante, chaque ligne du tableau doit être mise à jour . Ou non?

Le tableau sera gonflé à deux fois sa taille s'il ne peut pas réutiliser des tuples morts ou de l'espace libre sur les pages de données. Les performances de l'opération pourraient bénéficier grandement d'un nombre FILLFACTORinférieur à 100 ou simplement de tuples morts aléatoires répartis sur la table. Sinon, vous voudrez peut-être exécuter VACUUM FULL ANALYZEensuite pour récupérer l'espace disque. Mais ce ne sera pas rapide.

pgstattuple
Vous pouvez être intéressé par cette extension. Il vous aide à collecter des statistiques sur vos tables. Pour en savoir plus sur les tuples morts et l'espace libre:

Installez l'extension une fois par databae:

CREATE EXTENSION pgstattuple;

Appel:

SELECT * FROM pgstattuple('tbl');

Alternative

Si vous pouvez vous permettre de créer une nouvelle table, qui casserait les vues dépendantes, les clés étrangères, ...

Créez une copie vide de l'ancienne table:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

Ajoutez la colonne bigserial:

ALTER new_tbl ADD column bar bigserial;

INSÉRER les données de l'ancienne table, remplissant automatiquement la grande série:

INSERT INTO new_tbl
SELECT *    --  new column will be filled with default
FROM   old_tbl
ORDER  BY something; -- or don't order if you don't care: faster

La nouvelle colonne bigserial est manquante dans le SELECT de l'INSERT et sera automatiquement remplie avec sa valeur par défaut . Vous pouvez épeler toutes les colonnes et ajouter nextval()à la SELECTliste au même effet.

Assurez-vous d'avoir toutes vos données dans le nouveau tableau.
Ajoutez des index, des contraintes, des déclencheurs que vous aviez dans l'ancienne table maintenant .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

Cela pourrait être un peu plus rapide dans l'ensemble. Cela vous laisse avec une table vanille (et des index) sans aucun ballonnement.

Vous avez besoin d'espace disque libre - autour de la taille de l'ancienne table, en fonction de l'état de la table - comme salle de manœuvre. Mais vous en aurez peut-être autant besoin avec la première méthode simple à cause du ballonnement de la table. Encore une fois, les détails dépendent de l'état de votre table.

Erwin Brandstetter
la source
3
Enveloppez l'alternative dans une seule transaction, ce sera beaucoup plus rapide. Cela évitera des fsyncs supplémentaires
Frank Heikens