Au lieu de créer une nouvelle table, vous pouvez également réinsérer des lignes uniques dans la même table après l'avoir tronquée. Tout faire en une seule transaction .
Cette approche n'est utile que lorsqu'il y a beaucoup de lignes à supprimer dans toute la table. Pour quelques doublons seulement, utilisez une simple commande DELETE
.
Vous avez mentionné des millions de rangs. Pour que l'opération rapide vous voulez allouer suffisamment tampons temporaires pour la session. Le réglage doit être ajusté antes de tout tampon temporaire est utilisé dans votre session actuelle. Déterminez la taille de votre table :
SELECT pg_size_pretty(pg_relation_size('tbl'));
Définir temp_buffers
au moins un peu plus que ça.
SET temp_buffers = 200MB; -- example value
BEGIN;
CREATE TEMP TABLE t_tmp AS -- retains temp for duration of session
SELECT DISTINCT * FROM tbl -- DISTINCT folds duplicates
ORDER BY id; -- optionally "cluster" data
TRUNCATE tbl;
INSERT INTO tbl
SELECT * FROM t_tmp; -- retains order (implementation detail)
COMMIT;
Cette méthode peut être supérieure à la création d'une nouvelle table. si les objets dépendants existent. Vues, index, clés étrangères ou autres objets faisant référence à la table. TRUNCATE
vous fait de toute façon commencer avec une ardoise propre (nouveau fichier en arrière-plan) et est beaucoup plus vite que DELETE FROM tbl
avec de grandes tables ( DELETE
peut en fait être plus rapide avec de petites tables).
Pour les grandes tables, il est régulièrement plus rapide pour supprimer les index et les clés étrangères (FK), remplir à nouveau la table et recréer ces objets. En ce qui concerne les contraintes FK, vous devez être certain que les nouvelles données sont valides, bien sûr, ou vous rencontrerez des exceptions en essayant de créer la FK.
Notez que TRUNCATE
nécessite un verrouillage plus agressif que DELETE
. Cela peut poser un problème pour les tables soumises à une charge importante et simultanée. Mais c'est toujours moins perturbant que d'abandonner et de remplacer complètement la table.
Si TRUNCATE
n'est pas une option ou généralement pour tables petites à moyennes il existe une technique similaire avec un CTE de modification des données (Postgres 9.1 +) :
WITH del AS (DELETE FROM tbl RETURNING *)
INSERT INTO tbl
SELECT DISTINCT * FROM del;
ORDER BY id; -- optionally "cluster" data while being at it.
Plus lent pour les grandes tables, car TRUNCATE
est plus rapide là-bas. Mais il peut être plus rapide (et plus simple !) pour les petites tables.
Si vous n'avez aucun objet dépendant, vous pouvez créer une nouvelle table et supprimer l'ancienne, mais vous ne gagnez pratiquement rien par rapport à cette approche universelle.
Pour les très grandes tables qui ne rentreraient pas dans RAM disponible en créant un nouveau sera considérablement plus rapide. Vous devrez peser le pour et le contre par rapport à d'éventuels problèmes ou frais généraux liés à des objets dépendants.