La forma más eficiente de agregar una columna en serie a una tabla enorme

10

¿Cuál es la forma más rápida de agregar una columna BIGSERIAL a una tabla enorme (~ 3 filas Bil., ~ 174Gb)?

EDITAR:

  • Quiero que la columna tenga valores incrementados para las filas existentes ( NOT NULL).
  • No configuré un factor de relleno (que parece una mala decisión en retrospectiva).
  • No tengo ningún problema con el espacio en disco, solo quiero que sea lo más rápido posible.
Thi Duong Nguyen
fuente

Respuestas:

12

Qué hay de malo en:

ALTER TABLE foo ADD column bar bigserial;

Se rellenará con valores únicos automáticamente (comenzando con 1).

Si desea un número para cada fila existente, cada fila de la tabla debe actualizarse . O no?

La tabla se hinchará al doble de su tamaño si no puede reutilizar tuplas muertas o espacio libre en las páginas de datos. El rendimiento de la operación podría beneficiarse mucho de FILLFACTORmenos de 100 o solo tuplas muertas aleatorias repartidas sobre la mesa. De lo contrario, puede ejecutar VACUUM FULL ANALYZEdespués para recuperar espacio en disco. Sin embargo, esto no será rápido.

pgstattuple
Te puede interesar esta extensión. Le ayuda a recopilar estadísticas en sus tablas. Para conocer las tuplas muertas y el espacio libre:

Instale la extensión una vez por databae:

CREATE EXTENSION pgstattuple;

Llamada:

SELECT * FROM pgstattuple('tbl');

Alternativa

Si puede permitirse el lujo de crear una nueva tabla, que se rompería dependiendo de las vistas, claves externas, ...

Cree una copia vacía de la tabla anterior:

CREATE new_tbl AS
SELECT *
FROM   old_tbl
LIMIT  0;

Agregue la columna bigserial:

ALTER new_tbl ADD column bar bigserial;

INSERTE datos de la tabla anterior, llenando automáticamente el bigserial:

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

Falta la nueva columna bigserial en SELECT del INSERT y se rellenará con su valor predeterminado automáticamente . Puede deletrear todas las columnas y agregarlas nextval()a la SELECTlista con el mismo efecto.

Asegúrese de tener todos sus datos en la nueva tabla.
Agregue índices, restricciones, disparadores que tenía en la tabla anterior ahora .

DROP TABLE old_tbl;
ALTER TABLE new_tbl RENAME TO old_tbl;

Podría ser bastante más rápido en general. Esto te deja con una tabla de vainilla (e índices) sin ninguna hinchazón.

Necesita espacio libre en disco, aproximadamente del tamaño de la tabla anterior, dependiendo del estado de la tabla, como espacio de maniobra. Pero es posible que necesite tanto con el primer método simple debido a la hinchazón de la tabla. Nuevamente, los detalles dependen del estado de su tabla.

Erwin Brandstetter
fuente
3
Envuelva la alternativa en una sola transacción, eso será mucho más rápido. fsync
Evitará