web-dev-qa-db-fra.com

xmin non engagé pendant l'aspirateur, que faire?

Passage sous vide sur deux tables spécifiques de ma base de données PostgreSQL 10 dans l'erreur suivante:

VACUUM (FULL|ANALYZE|FREEZE|) table;
ERROR:  uncommitted xmin 359569171 from before xid cutoff 435784199 needs to be frozen

Les tables fonctionnent par ailleurs, je peux les interroger/insérer/les mettre à jour (je peux interroger les tables entières sans aucune erreur). Je peux aussi les réindex. Cependant, cette erreur arrête l'analysement du vide nocturne sur toute la base de données prématurément. La valeur de valeur XMIN semble être constante, la valeur de coupure augmente monotone.

Comment puis-je réparer cela? Depuis les très rares instances sur le Web avec une erreur similaire (par exemple https://stackoverflow.com/questions/50354521/postgres-corruption-error-duplicate-rows-with-the-same-prima -key ), il semble qu'il devrait y avoir des mauvaises lignes, mais je ne peux pas sembler les trouver.

2
P.Péter

Une solution quelque peu élégante qui n'a besoin de temps d'arrêt

Je peux trouver les lignes spécifiques et mettre à jour une colonne insignifiante (commentaire dans mon cas) en eux à sa valeur actuelle:

SELECT id, comment FROM table WHERE xmin=359569171;

et puis avec les résultats, effectuez des mises à jour de chaque ligne.

UPDATE table SET comment=(SELECT comment FROM table WHERE id=<ID>) WHERE id=<ID>;

Comme il n'y avait que trois rangées, je n'ai pas pris la peine de créer un script formalisé.

Vieille solution de force brute

C'est ce que je pouvais trouver d'abord et ce n'est pas le moyen le plus élégant de se débarrasser du message. Je viderai simplement la table, supprimez toutes les lignes, puis la restauez-la. Ceci est le script shell que j'ai créé, quelqu'un peut le trouver utile.

#!/bin/bash

DB=database_name

for TABLE
do
    SAVEFILE=/tmp/$TABLE.sql.gz
    echo "dumping $TABLE to $SAVEFILE"
    su - postgres -c pg_dump $DB --table=$TABLE --data-only | pigz -1 > $SAVEFILE"
    echo "disabling triggers for $TABLE"
    su - postgres -c "psql  $DB -c 'ALTER TABLE $TABLE DISABLE TRIGGER ALL'"
    echo "deleting the contents of $TABLE"
    su - postgres -c "psql $DB -c 'DELETE FROM $TABLE'"
    echo "restoring contents of $TABLE"
    zcat $SAVEFILE | su - postgres -c "psql $DB"
    echo "re-enabling triggers for $TABLE"
    su - postgres -c "psql $DB -c 'ALTER TABLE $TABLE ENABLE TRIGGER ALL'"
done

L'inconvénient de cette approche est que la demande doit être arrêtée au cours de cette opération pour éviter les incohérences, car les déclencheurs doivent être arrêtés pour la table. Cela provoque environ une demi-heure de temps d'arrêt dans mon cas.

J'ai essayé cette approche sur une copie de la base de données et cela fonctionne, mais je cherche toujours une meilleure solution pouvant être faite sans aucun temps d'arrêt.

1
P.Péter