Files
nas-runbooks/common/n8n-insights-collation-index-doublons.md
T

4.2 KiB

n8n — index unique dégradé sur insights_metadata (collation Postgres)

Date : 2026-07-23 · Tags : n8n, postgres, collation, index, insights · Statut : clos — laissé en l'état (décision assumée)

Contexte

Stack n8n NAS (Portainer stack 254, DB n8n-DB / postgres 17-alpine, bind-mount /volume1/docker/n8n/db). Après la MAJ n8n 2.23.0 → 2.31.5, les tables insights_* (analytique interne n8n) présentaient des chiffres surestimés.

Symptôme

Toute session psql sur la base affiche :

WARNING:  database "n8n" has no actual collation version, but a version was recorded

Conséquence : l'index unique IDX_1d8ab99d5861c9388d2dc1cf73 sur insights_metadata(workflowId) est dégradé — il a laissé entrer des doublons. État constaté : 8 doublons de metadata, ~13 workflows légèrement surcomptés dans les insights. 69 lignes dans insights_metadata.

Cause : la version de collation enregistrée dans le catalogue ne correspond plus à celle de la libc du conteneur (bascule d'image / de libc). Les index B-tree sur colonnes texte construits sous l'ancienne collation deviennent incohérents → l'unicité n'est plus garantie.

Ce qui NE MARCHE PAS

Restore littéral du dump insights_*

Le réflexe « TRUNCATE + COPY depuis le backup » échoue :

BEGIN
TRUNCATE TABLE
ERROR:  duplicate key value violates unique constraint "IDX_1d8ab99d5861c9388d2dc1cf73"
DETAIL:  Key ("workflowId")=(XNppr5IcEMfJ73Ep) already exists.
CONTEXT:  COPY insights_metadata, line 31

Pourquoi : le TRUNCATE vide l'index, qui se reconstruit au fil du COPY sous la collation courante → il redevient strict. Or le backup contient les doublons d'origine (entrés à l'époque où l'index était dégradé). Le restore se mord la queue.

Le garde-fou a fonctionné : psql -v ON_ERROR_STOP=1 + BEGIN explicite → rollback complet, table inchangée (69 lignes avant/après). Toujours encadrer un restore partiel par ON_ERROR_STOP + transaction.

Comptages naïfs

Avec un index dégradé, les SELECT count(*) peuvent passer par l'index et renvoyer des chiffres incohérents. Forcer le parcours séquentiel pour un état fiable :

SET enable_indexscan = off;
SET enable_bitmapscan = off;
SELECT count(*) FROM insights_metadata;

Ce qui marche

Option A — restore dédupliqué (non retenue)

Dédupliquer les données hors ligne (sur le dump, données statiques → fiable, insensible à l'index dégradé), puis TRUNCATE + COPY du fichier propre. L'index unique reconstruit l'accepte. Atomique, faible risque, mais perd le churn depuis le dump.

Option B — ne rien faire (RETENUE le 23/07/2026)

Les insights sont de l'analytique bas-enjeu, et n8n churne la table en continu : observé en direct, insights_raw 49 → 0 et insights_by_period 19347 → 19363 pendant la session (compaction en tâche de fond). Le surcomptage s'atténue seul avec la rétention. → Aucune chirurgie. Aucune perte de données, aucun impact fonctionnel sur les workflows.

⚠️ Bombe à retardement (à connaître avant tout geste futur)

Tant que les doublons sont présents, échoueront :

  • REINDEX (index ou base)
  • ALTER DATABASE n8n REFRESH COLLATION VERSION
  • pg_upgrade
  • tout dump/restore complet de la base

Si l'un de ces gestes devient nécessaire (montée de version postgres, changement d'image), dédupliquer insights_metadata AVANT :

-- inspection préalable
SELECT "workflowId", count(*) FROM insights_metadata GROUP BY 1 HAVING count(*) > 1;

Prévention

  • Pin le patch postgres exact dans le compose du stack (ex. postgres:17.10-alpine), jamais postgres:17 flottant — c'est une bascule mineure/libc implicite qui produit ce type de désynchro de collation. Cf. RUNBOOK-HERMES-UPDATE.md et le piège 2 du stack n8n.
  • Après toute bascule d'image postgres, guetter le WARNING ... collation version en tête de session psql.

Accès rapide

ssh nas 'export PATH=$PATH:/usr/local/bin; docker exec -i n8n-DB psql -U n8nuser -d n8n' <<'SQL' 2>&1 | grep -vi "collation version"
SELECT count(*) FROM insights_metadata;
SQL

Voir aussi : common/n8n-credentials-corruption-veille-consolidation.md, common/ports-registry.md.