Как я исправил таблицу в postgres

Я пишу этот пост о ошибке отсутствующего чанка в таблице PostgreSQL, из-за которой не удавались мои ежедневные резервные копии. Мне удалось решить проблему, и я хочу описать использованный метод на случай, если он окажется полезен кому-то ещё, столкнувшемуся с этой проблемой. Ни в коем случае это не руководство или профессиональные инструкции по правильному решению ошибок отсутствующих чанков в PostgreSQL, так как я не эксперт и действовал, не обладая глубокими знаниями, но в итоге всё сработало.

Ошибка, которую я получал при создании резервных копий:

 pg_dump: error: Dumping the contents of table "stylesheet_cache" failed: PQgetResult() failed.
 pg_dump: error: Error message from server: ERROR:  missing chunk number 0 for toast value 1903804 in pg_toast_22663
 pg_dump: error: The command was: COPY public.stylesheet_cache (id, target, digest, content, created_at, updated_at, theme_id, source_map) TO stdout;

Таким образом, проблема заключалась в таблице stylesheet_cache: ERROR: missing chunk number 0 for toast value 1903804 in pg_toast_22663.

Я использую Discourse в Docker, поэтому вот что я сделал:

ssh into the server
cd /path/to/discourse
./launcher rebuild app
su postgres -c "psql discourse"

Попадая в PostgreSQL, я попытался выполнить REINDEX таблицы в надежде, что это решит проблему.

discourse=# select reltoastrelid::regclass from pg_class where relname = 'stylesheet_cache';
      reltoastrelid      
-------------------------
 pg_toast.pg_toast_18396
(1 row)
REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_18396;
VACUUM analyze stylesheet_cache;

Попытался сделать резервную копию снова, но она всё ещё не удалась, поэтому мне пришлось продолжить поиск повреждения.

Я вычислил общее количество строк в своей таблице с помощью:

select count(*) from stylesheet_cache;

Получил результат 2260 строк.

Затем я начал искать именно повреждённую строку и удалить её. Я предположил, что stylesheet_cache — это не то, что может действительно сломать всю мою базу данных. Как я уже упоминал, я не эксперт, поэтому, возможно, я проявил излишнюю смелость. Будьте осторожны при выполнении подобных действий, так как вы можете повредить свою базу данных.

Я использовал запросы с LIMIT и OFFSET для поиска повреждённых строк:

select * from stylesheet_cache order by id limit 100 offset 0;

Я менял значения OFFSET и LIMIT, пока не получил ошибку «Missing chunk…», после чего сузил поиск до LIMIT 1 и конкретного OFFSET повреждённой строки. В моём случае было повреждено 5 строк.

Вы могли бы использовать shell-скрипт для поиска строки с меньшими усилиями. Я выбрал ручной метод, который занял некоторое время, но вы можете использовать следующий скрипт:

#!/bin/sh
j=0
while [ $j -lt 2260 ]
do
  psql -U postgres -d discourse -c "SELECT * FROM stylesheet_cache LIMIT 1 offset $j" > /dev/null || echo $j
  j=$(($j+1))
done

Я нашёл ID повреждённой строки с помощью следующей команды:

select id from stylesheet_cache order by id limit 1 offset 450;

id

----

11498

Итак, ID моей повреждённой строки был 11498.
Я удалил строку с помощью:

delete from stylesheet_cache where id = 11498;

После удаления повреждённых строк я снова выполнил REINDEX:

REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_40948;
VACUUM analyze stylesheet_cache;

И попытался сделать резервную копию снова. На этот раз всё сработало. Я руководствовался этими инструкциями по восстановлению PostgreSQL: Postgres error: Missing chunk 0 for toast value in pg_toast · GitHub

ДИСКЛЕЙМЕР: это не мнение эксперта, поэтому действуйте с осторожностью, если у вас возникли аналогичные повреждения отсутствующих чанков и вы пытаетесь их исправить.

3 лайка