J'ai rencontré un problème lors de l'interrogation de certaines de mes tables récemment. Lorsque j'essaie de sélectionner des données, j'obtiens une ERREUR indiquant: ERREUR: taille de demande d'allocation de mémoire invalide 4294967293. Cela indique généralement une corruption de données. Il y a une technique gentille et précise de comment supprimer des rangées corrompues décrites ici: https://confluence.atlassian.com/jirakb/invalid-memory-alloc-request-size-440107132.html
Mais, puisque j'ai beaucoup de tables corrompues, cette méthode est trop lente. Donc, j'ai trouvé une bonne fonction qui renvoie le dernier ctid réussi ici: http://blog.dob.sk/2012/05/19/fixing-pg_dump-invalid-memory-alloc-request-size/Correction d'une demande d'allocation de mémoire invalide à PostgreSQL 9.2.9
Vous cherchez une ligne corrompue est un peu plus rapide lors de son utilisation, mais pas assez rapide. Je légèrement modifié pour stocker tous « dernier ctid réussi » dans une autre table et il ressemble maintenant à ceci:
CREATE OR REPLACE FUNCTION
find_bad_row(tableName TEXT)
RETURNS void
as $find_bad_row$
DECLARE
result tid;
curs REFCURSOR;
row1 RECORD;
row2 RECORD;
tabName TEXT;
count BIGINT := 0;
BEGIN
DROP TABLE IF EXISTS bad_rows_tbl;
CREATE TABLE bad_rows_tbl (id varchar(255), offs BIGINT);
SELECT reverse(split_part(reverse($1), '.', 1)) INTO tabName;
OPEN curs FOR EXECUTE 'SELECT ctid FROM ' || tableName;
count := 1;
FETCH curs INTO row1;
WHILE row1.ctid IS NOT NULL LOOP
BEGIN
result = row1.ctid;
count := count + 1;
FETCH curs INTO row1;
EXECUTE 'SELECT (each(hstore(' || tabName || '))).* FROM '
|| tableName || ' WHERE ctid = $1' INTO row2
USING row1.ctid;
IF count % 100000 = 0 THEN
RAISE NOTICE 'rows processed: %', count;
END IF;
EXCEPTION
WHEN SQLSTATE 'XX000' THEN
RAISE NOTICE 'LAST CTID: %', result;
EXECUTE 'INSERT INTO bad_rows_tbl VALUES(' || result || ',' || count || ')';
END;
END LOOP;
CLOSE curs;
END
$find_bad_row$
LANGUAGE plpgsql;
Je suis tout à fait nouveau pour plpgsql, donc je suis coincé avec la question suivante: comment interroger pas pré-infructueux ctid, mais l'échec exact (ou calculer le suivant de pré-échoué) afin que je puisse l'insérer dans bad_rows_tbl et l'utiliser comme argument pour une déclaration DELETE plus loin?
Espoir pour un peu d'aide ...
UPD: une fonction que je fini par
CREATE OR REPLACE FUNCTION
find_bad_row(tableName TEXT)
RETURNS tid[]
as $find_bad_row$
DECLARE
result tid;
curs REFCURSOR;
row1 RECORD;
row2 RECORD;
tabName TEXT;
youNeedMe BOOLEAN = false;
count BIGINT := 0;
arrIter BIGINT := 0;
arr tid[];
BEGIN
CREATE TABLE bad_rows_tbl (id varchar(255), offs BIGINT);
SELECT reverse(split_part(reverse($1), '.', 1)) INTO tabName;
OPEN curs FOR EXECUTE 'SELECT ctid FROM ' || tableName;
count := 1;
FETCH curs INTO row1;
WHILE row1.ctid IS NOT NULL LOOP
BEGIN
result = row1.ctid;
count := count + 1;
IF youNeedMe THEN
arr[arrIter] = result;
arrIter := arrIter + 1;
RAISE NOTICE 'ADDING CTID: %', result;
youNeedMe = FALSE;
END IF;
FETCH curs INTO row1;
EXECUTE 'SELECT (each(hstore(' || tabName || '))).* FROM '
|| tableName || ' WHERE ctid = $1' INTO row2
USING row1.ctid;
IF count % 100000 = 0 THEN
RAISE NOTICE 'rows processed: %', count;
END IF;
EXCEPTION
WHEN SQLSTATE 'XX000' THEN
RAISE NOTICE 'LAST GOOD CTID: %', result;
youNeedMe = TRUE;
END;
END LOOP;
CLOSE curs;
RETURN arr;
END
$find_bad_row$
LANGUAGE plpgsql;
Comment es-tu dans la situation en premier lieu? Est-ce que la restauration à un point dans le temps (barman, etc) après la restauration à partir de la sauvegarde n'est pas une option? –
Malheureusement, étant donné que la commande 'archive_mode' dans postgresql.conf est commentée, je suppose que la récupération à un point dans le temps n'est pas disponible. C'est pourquoi j'essaye de réparer le contenu. –
J'ai modifié une requête et ajouté une fonction que j'ai terminée. Il renvoie un tableau de TID de lignes corrompues. Il peut être utilisé à une clause WHERE d'une instruction DELETE. J'ai déjà supprimé plusieurs lignes brisées en l'utilisant. –