web-dev-qa-db-fra.com

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

Quelle est la manière la plus rapide d'ajouter une colonne BIGSERIAL à une immense table (~ 3 lignes bil., ~ 174 Go)?

ÉDITER:

  • Je souhaite 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.
10
Thi Duong Nguyen

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 voulez 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 beaucoup d'un FILLFACTOR inférieur à 100 ou simplement de tuples morts aléatoires répartis sur la table. Sinon, vous souhaiterez peut-être exécuter VACUUM FULL ANALYZE Pour récupérer de l'espace disque. Mais ce ne sera pas rapide.

pgstattuple
Cette extension pourrait vous intéresser. 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 remplie automatiquement avec sa valeur par défaut . Vous pouvez épeler toutes les colonnes et ajouter nextval() à la liste SELECT dans le 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 Vanilla (et des index) sans aucun ballonnement.

Vous avez besoin d'espace disque libre - autour de la taille de l'ancienne table, selon 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.

12
Erwin Brandstetter