Usar una columna serial
Su plan es agregar un índice innecesariamente enorme para 40 millones (!) de filas. Y ni siquiera estás seguro de que va a ser único. Desaconsejaría encarecidamente esa ruta de acción. Agregue un serial
columna en su lugar y listo:
ALTER TABLE tbl ADD COLUMN tbl_id serial PRIMARY KEY;
Eso es todo lo que necesitas hacer. El resto sucede automáticamente. Más en el manual o en estas respuestas estrechamente relacionadas:
El incremento automático de la clave principal de PostgreSQL falla en C++
Función SQL de incremento automático
Agregar un serial
La columna es una operación de una sola vez, pero costosa. Se debe reescribir toda la tabla, bloqueando las actualizaciones mientras dure la operación. Es mejor hacerlo sin carga concurrente fuera del horario laboral. Cito el manual aquí
:
Dado que esto reescribe efectivamente toda la tabla, también puede crear una nueva tabla con una columna pk serial, insertar todas las filas de la tabla anterior, dejar que la serie se llene con los valores predeterminados de su secuencia, eliminar la anterior y cambiar el nombre de la nueva. Más información en estas respuestas estrechamente relacionadas:
Actualizar las filas de la base de datos sin bloquear la tabla en PostgreSQL 9.2
Agregar nueva columna sin tabla bloquear?
Asegúrese de que todas sus declaraciones INSERT tengan una lista de objetivos, luego una columna adicional no puede confundirlos:
INSERT INTO tbl (col1, col2, ...) VALUES ...
No:
INSERT INTO tbl VALUES ...
Una serial
se implementa con un integer
columna (4 bytes).
Se implementa una restricción de clave principal con un índice único y un NOT NULL
restricción en las columnas involucradas.
El contenido de un índice se almacena de manera muy similar a las tablas. Se necesita almacenamiento físico adicional por separado. Más información sobre el almacenamiento físico en esta respuesta relacionada:
Calcular y ahorrar espacio en PostgreSQL
Su índice incluiría 2 marcas de tiempo (2 x 8 bytes) más un nombre de archivo largo incl. ruta (¿~ 50 bytes?) Eso haría que el índice fuera alrededor de 2,5 GB más grande (40M x 60 .. algo de bytes) y todas las operaciones más lentas.
Lidiar con duplicados
Cómo lidiar con la "importación de duplicados" depende de cómo estés importando datos y cómo se defina exactamente "duplicado".
Si estamos hablando de COPY
declaraciones, una forma sería usar una tabla de preparación temporal y colapsar los duplicados con un simple SELECT DISTINCT
o DISTINCT ON
en el INSERT
comando:
CREATE TEMP TABLE tbl_tmp AS
SELECT * FROM tbl LIMIT 0; -- copy structure without data and constraints
COPY tbl_tmp FROM '/path/to/file.csv';
INSERT INTO tbl (col1, col2, col3)
SELECT DISTINCT ON (col1, col2)
col1, col2, col3 FROM tbl_tmp;
O, para prohibir también duplicados con filas ya existentes:
INSERT INTO tbl (col1, col2, col3)
SELECT i.*
FROM (
SELECT DISTINCT ON (col1, col2)
col1, col2, col3
FROM tbl_tmp
) i
LEFT JOIN tbl t USING (col1, col2)
WHERE t.col1 IS NULL;
la temperatura la tabla se elimina automáticamente al final de la sesión.
Pero la solución adecuada sería ocuparse de la raíz del error que produce duplicados en primer lugar.
Pregunta original
1) No podría agregar el pk en absoluto, si hay un solo duplicado en todas las columnas.
2) Solo tocaría una base de datos PostgreSQL versión 8.1 con un poste de cinco pies. Es irremediablemente antiguo, desactualizado e ineficiente, ya no es compatible y probablemente tenga una serie de agujeros de seguridad sin reparar. Sitio oficial de control de versiones de Postgres.
@David
ya proporcionó la instrucción SQL.
3 y 4) Una violación de clave duplicada. PostgreSQL arrojar un error también significa que toda la transacción se revierte. Capturar eso en un script de Perl no puede hacer que el resto de la transacción se lleve a cabo. Tendría que crear una secuencia de comandos del lado del servidor con plpgsql, por ejemplo, donde puede detectar excepciones.