web-dev-qa-db-fra.com

Postgres n'a pas pu créer d'index unique, la clé est dupliquée

J'essaie d'ajouter une colonne à une table de ma base de données Postgres 9.3 avec ce SQL apparemment simple:

ALTER TABLE quizzes ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT false;

Cependant, j'obtiens l'erreur suivante:

ERROR:  could not create unique index "quizzes_pkey"
DETAIL:  Key (id)=(10557462) is duplicated.

Curieusement, il n'y a en fait pas de lignes avec cet id (qui est la clé primaire, donc il ne devrait pas y avoir de doublons):

SELECT id FROM quizzes WHERE id = 10557462;
 id 
----
(0 rows)

En fait, il semblerait que cet identifiant ait été ignoré:

SELECT id FROM quizzes WHERE id > 10557459 ORDER BY id LIMIT 4;
    id    
----------
 10557460
 10557461
 10557463
 10557464
(4 rows)

Pourquoi est-ce que cela m'empêche d'ajouter une colonne et comment puis-je résoudre ce problème?

5
Rob Johansen

Je soupçonne que vous avez des problèmes de corruption d'index ou de visibilité préexistants.

Lorsque vous ALTER TABLE ... ADD COLUMN ... DEFAULT ..., il effectue une réécriture de table complète. Cela reconstruit tous les index, en notant le problème sur le tas.

Vous constaterez probablement que VACUUM FULL sur la table produit la même erreur.

J'attends cela

BEGIN;
SET LOCAL enable_indexscan = off;
SET LOCAL enable_bitmapscan = off;
SET LOCAL enable_indexonlyscan = off; 
SELECT ctid,xmin,xmax,id FROM quizzes WHERE id = 10557462;
ROLLBACK;

révélera que les n-uplets existent réellement.

Veuillez tout d'abord lire et agir sur cette page wiki . Une fois que vous avez fait cela, vérifiez votre version. Exécutez-vous ou avez-vous déjà exécuté une version de PostgreSQL 9.3 antérieure à 9.3.9? Surtout comme une réplique qui a ensuite été promue? Si c'est le cas, cela l'explique probablement à cause des bogues multixact connus qui ont été corrigés ici:

Sinon, difficile de dire ce qui se passe. Il serait nécessaire de jeter un coup d'œil sur la (les) page (s) à problèmes du tas utilisant pageinspect, à la sortie pg_controldata, et éventuellement aux pages de l'arborescence binaire faisant référence à ces pages.

6
Craig Ringer

J'ai accepté la réponse de @Craig Ringer parce que je n'aurais jamais pu résoudre le problème sans cela. Si cela peut aider quelqu'un d'autre, voici la requête exacte que j'ai utilisée pour résoudre le problème (heureusement pour moi, les doublons peuvent être supprimés):

BEGIN;
SET LOCAL enable_indexscan = off;
SET LOCAL enable_bitmapscan = off;
SET LOCAL enable_indexonlyscan = off; 
DELETE FROM quizzes WHERE id = 10557462;
COMMIT;

Après cela, ma requête initiale a finalement réussi:

ALTER TABLE quizzes ADD COLUMN deleted BOOLEAN NOT NULL DEFAULT false;
1
Rob Johansen