diff --git a/common/n8n-insights-collation-index-doublons.md b/common/n8n-insights-collation-index-doublons.md new file mode 100644 index 0000000..a58bba3 --- /dev/null +++ b/common/n8n-insights-collation-index-doublons.md @@ -0,0 +1,92 @@ +# 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 : + +```sql +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** : + +```sql +-- 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 + +```bash +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`.