Ошибка субд xx000 error missing chunk number 0 for toast value 1c
У меня есть несколько ошибок с моим postgresql db, который возник после перенапряжения:
Я не могу получить доступ ко многим таблицам из моей базы данных. Когда я пытаюсь, например, select * from ac_cash_collection , я получаю ошибку обмана:
когда я пытаюсь pg_dump Я получаю следующую ошибку:
Я пошел вперед и попытался запустить reindex всей базы данных, я на самом деле я оставил это runnng, пошел спать, и я обнаружил, что утром ничего не сделал, поэтому мне пришлось отменить его.
ОТВЕТЫ
Ответ 1
Я не знаю, помогают ли они против тостов. В любом случае, если их установка заставляет вашу базу данных снова стать пригодной для использования, я бы сделал , чтобы снова вернуть все таблицы и каталоги в новорожденную форму. Успех!
Ответ 2
Если у вас есть резервные копии, просто восстановите их.
Если нет - вы только что узнали, зачем нужны регулярные резервные копии. Там ничего не может сделать PostgreSQL, если аппаратное обеспечение неверно.
Кроме того, если вы когда-нибудь снова окажетесь в этой ситуации, сначала остановите PostgreSQL и возьмите полную резервную копию всего уровня - все табличные пространства, WAL и т.д. Таким образом, у вас есть известная отправная точка.
Итак - если вы все еще хотите восстановить некоторые данные.
- Попробуйте сбросить отдельные таблицы. Получите то, что вы можете таким образом.
- Отбрасывать индексы, если они вызывают проблемы.
- Дамп разделов таблиц (id = 0..9999, 1000..19999 и т.д.) - таким образом вы можете определить, где некоторые строки могут быть повреждены, и сбросить все меньшие разделы, чтобы восстановить то, что все еще хорошо.
- Попробуйте сбросить только определенные столбцы - большие текстовые значения хранятся вне очереди (в таблицах с тостами), поэтому их можно избежать извлечения остальных данных.
- Если у вас есть поврежденные системные таблицы, вы получаете много работы.
Это много работы, и тогда вам нужно будет пройти и проверить, что вы восстановили, и попытаться выяснить, что отсутствует/неверно.
Есть много вещей, которые вы можете сделать (создание пустых блоков в некоторых случаях может позволить вам сбрасывать частичные данные), но они все сложнее и сложнее, и если данные не являются особенно ценными, не стоит усилий.
Ответ 3
Прежде чем делать что-либо, сделайте полную копию поврежденной базы данных на уровне файловой системы.
Неспособность сделать это уничтожает доказательства о том, что вызвало коррупцию, и означает, что если ваши усилия по восстановлению ухудшаются и ухудшаются, вы не можете их отменить.
На файловой базе были такие ошибки. В таких ситуациях, открывал базу утилитой, которая даёт доступ к таблицам, и заменял руками значение, которое требует платформа, в вашем случае, она 0 хочет. 2-3 раза повторял махинацию, и проблема пропадала.
Тем более если база не файловая, то никакие утилиты не нужны.
Ничего не помогло.REINDEX table pg_toast.pg_toast_2549433; - реиндексация проходит нормально
VACUUM ANALYZE [table] -- вываливается та же ошибка
Не работает pg_dump, та же ошибка, архив базы не создается.
А как/чем этот регистр изменяется? Вручную, документом(-ами)?
В режиме Предприятие пробовали этот регистр открыть, посмотреть что там?
Если он изменяется документами, то не пробовали эти документы перепровести?
Если этот регистр можно изменять вручную, то не пробовали в него добавлять записи?
В клиент-серверном варианте есть режим "Тестирование и исправление ИБ"? (в файловом варианте такой есть в Конфигураторе)
В режиме Предприятие пробовали этот регистр открыть, посмотреть что там? В клиент-серверном варианте есть режим "Тестирование и исправление ИБ"? Ошибка СУБДERROR: unexpected chunk number 37 (expected 0) for toast value 9333560 in pg_toast_2549433
А в самой Postgresql есть свои средства тестирования и исправления?
А в самой Postgresql есть свои средства тестирования и исправления?(11) Я в клиент-сервере профан, чисто из любознательности интересуюсь, для общего развития ))
В репозитории моей Debian GNU/Linux куча разных пакетов по Постгрес, в том числе полный комплект документации. В принципе, могу хоть сейчас себе установить и начать вместе с вами в эту СУБД погружаться ))
Подозреваю, что без такого погружения вашу проблему не решить.
А как именно вы пытались восстановить таблицу через Постгрес? Что пробовали делать?
Вот что у меня в репозитории пакетов есть по поводу клиентских программулин (фронт-эндов) для Постгрес. Пишут, что удалять таблицы можно, ну значит наверняка и для прямого редактирования этих самых таблиц есть какие-то средства:
Package: postgresql-client-9.6
Description: front-end programs for PostgreSQL 9.6
This package contains client and administrative programs for PostgreSQL: these are the interactive terminal client psql
and programs for creating and removing users and databases.
This is the client package for PostgreSQL 9.6. If you install PostgreSQL 9.6 on a standalone machine, you need the
server package postgresql-9.6, too. On a network, you can install this package on many client machines, while the server
package may be installed on only one machine.
Хочу поделиться с вами моим первым успешным опытом восстановления полной работоспособности базы данных Postgres. С СУБД Postgres я познакомился пол года назад, до этого опыта администрирования баз данных у меня не было совсем.
Я работаю полу-DevOps инженером в крупной IT-компании. Наша компания занимается разработкой программного обеспечения для высоконагруженных сервисов, я же отвечаю за работоспособность, сопровождение и деплой. Передо мной поставили стандартную задачу: обновить приложение на одном сервере. Приложение написано на Django, во время обновления выполняются миграции (изменение структуры базы данных), и перед этим процессом мы снимаем полный дамп базы данных через стандартную программу pg_dump на всякий случай.
Во время снятия дампа возникла непредвиденная ошибка (версия Postgres – 9.5):
Ошибка «invalid page in block» говорит о проблемах на уровне файловой системы, что очень нехорошо. На различных форумах предлагали сделать FULL VACUUM с опцией zero_damaged_pages для решения данной проблемы. Что же, попрробеум…
Подготовка к восстановлению
ВНИМАНИЕ! Обязательно сделайте резервную копию Postgres перед любой попыткой восстановить базу данных. Если у вас виртуальная машина, остановите базу данных и сделайте снепшот. Если нет возможности сделать снепшот, остановите базу и скопируйте содержимое каталога Postgres (включая wal-файлы) в надёжное место. Главное в нашем деле – не сделать хуже. Прочтите это.
Поскольку в целом база у меня работала, я ограничился обычным дампом базы данных, но исключил таблицу с повреждёнными данными (опция -T, --exclude-table=TABLE в pg_dump).
Сервер был физическим, снять снепшот было невозможно. Бекап снят, двигаемся дальше.
Проверка файловой системы
В моём случае файловая система с базой данных была примонтирована в «/srv» и тип был ext4.
Останавливаем базу данных: systemctl stop [email protected] и проверяем, что файловая система никем не используется и её можно отмонтировать с помощью команды lsof:
lsof +D /srv
Мне пришлось ещё остановить базу данных redis, так как она тоже исползовала "/srv". Далее я отмонтировал /srv (umount).
Проверка файловой системы была выполнена с помощью утилиты e2fsck с ключиком -f (Force checking even if filesystem is marked clean):
Далее с помощью утилиты dumpe2fs (sudo dumpe2fs /dev/mapper/gu2--sys-srv | grep checked) можно убедиться, что проверка действительно была произведена:
e2fsck говорит, что проблем на уровне файловой системы ext4 не найдено, а это значит, что можно продолжать попытки восстановить базу данных, а точнее вернуться к vacuum full (само собой, необходимо примонтирвоать файловую систему обратно и запустить базу данных).
Если у вас сервер физический, то обязательно проверьте состояние дисков (через smartctl -a /dev/XXX) либо RAID-контроллера, чтобы убедиться, что проблема не на аппаратном уровне. В моём случае RAID оказался «железный», поэтому я попросил местного админа проверить состояние RAID (сервер был в нескольких сотнях километров от меня). Он сказал, что ошибок нет, а это значит, что мы точно можем начать восстановление.
Попытка 1: zero_damaged_pages
Подключаемся к базе через psql аккаунтом, обладающим правами суперпользователя. Нам нужен именно суперпользователь, т.к. опцию zero_damaged_pages может менять только он. В моём случае это postgres:
psql -h 127.0.0.1 -U postgres -s [database_name]
Опция zero_damaged_pages нужна для того, чтобы проигнорировать ошибки чтения (с сайта postgrespro):
При выявлении повреждённого заголовка страницы Postgres Pro обычно сообщает об ошибке и прерывает текущую транзакцию. Если параметр zero_damaged_pages включён, вместо этого система выдаёт предупреждение, обнуляет повреждённую страницу в памяти и продолжает обработку. Это поведение разрушает данные, а именно все строки в повреждённой странице.
Включаем опцию и пробуем делать full vacuum таблицы:
К сожалению, неудача.
Мы столкнулись с аналогичной ошибкой:
pg_toast – механизм хранения «длинных данных» в Postgres, если они не помещаются в одну страницу (по умолчанию 8кб).
Попытка 2: reindex
Первый совет из гугла не помог. После нескольких минут поиска я нашёл второй совет – сделать reindex повреждённой таблицы. Этот совет я встречал во многих местах, но он не внушал доверия. Сделаем reindex:
reindex завершился без проблем.
Однако это не помогло, VACUUM FULL аварийно завершался с аналогичной ошибкой. Поскольку я привык к неудачам, я стал искать советов в интернете дальше и наткнулся на довольно интересную статью.
Попытка 3: SELECT, LIMIT, OFFSET
В статье выше предлагали посмотреть таблицу построчно и удалить проблемные данные. Для начала необходимо было просмотреть все строки:
В моём случае таблица содержала 1 628 991 строк! По-хорошему необходимо было позаботиться о партициирвоании данных, но это тема для отдельного обсуждения. Была суббота, я запустил вот эту команду в tmux и пошёл спать:
К утру я решил проверить, как обстоят дела. К моему удивлению, я обнаружил, что за 20 часов было просканировано только 2% данных! Ждать 50 дней я не хотел. Очередной полный провал.
Но я не стал сдаваться. Мне стало интересно, почему же сканирование шло так долго. Из документации (опять на postgrespro) я узнал:
OFFSET указывает пропустить указанное число строк, прежде чем начать выдавать строки.
Если указано и OFFSET, и LIMIT, сначала система пропускает OFFSET строк, а затем начинает подсчитывать строки для ограничения LIMIT.
Применяя LIMIT, важно использовать также предложение ORDER BY, чтобы строки результата выдавались в определённом порядке. Иначе будут возвращаться непредсказуемые подмножества строк.
Очевидно, что вышенаписанная команда была ошибочной: во-первых, не было order by, результат мог получиться ошибочным. Во-вторых, Postgres сначала должен был просканировать и пропустить OFFSET-строк, и с возрастанием OFFSET производительность снижалась бы ещё сильнее.
Попытка 4: снять дамп в текстовом виде
Далее мне в голову пришла, казалось бы, гениальная идея: снять дамп в текстовом виде и проанализировать последнюю записанную строку.
Но для начала, ознакомимся со структурой таблицы ws_log_smevlog:
В нашем случае у нас есть столбец «id», который содержал уникальный идентификатор (счётчик) строки. План был такой:
- Начинаем снимать дамп в текстовом виде (в виде sql-команд)
- В определённый момент времени снятия дампа бы прервалось из-за ошибки, но тектовый файл всё равно сохранился бы на диске
- Смотрим конец текстового файла, тем самым мы находим идентификатор (id) последней строки, которая снялась успешно
Снятия дампа, как и ожидалось, прервался с той же самой ошибкой:
Далее через tail я просмотрел конец дампа (tail -5 ./my_dump.dump) обнаружил, что дамп прервался на строке с id 186 525. «Значит, проблема в строке с id 186 526, она битая, её и надо удалить!» – подумал я. Но, сделав запрос в базу данных:
«select * from ws_log_smevlog where обнаружилось, что с этой строкой всё нормально… Строки с индексами 186 530 — 186 540 тоже работали без проблем. Очередная «гениальная идея» провалилась. Позже я понял, почему так произошло: при удалении\изменении данных из таблицы они не удаляются физически, а помечаются как «мёртвые кортежи», далее приходит autovacuum и помечает эти строки удалёнными и разрешает использовать эти строки повторно. Для понимания, если данные в таблице меняются и включён autovacuum, то они не хранятся последовательно.
Попытка 5: SELECT, FROM, WHERE > Неудачи делают нас сильнее. Не стоит никогда сдаваться, нужно идти до конца и верить в себя и свои возможности. Поэтому я решил попробовать ешё один вариант: просто просмотреть все записи в базе данных по одному. Зная структуру моей таблицы (см. выше), у нас есть поле id, которое является уникальным (первичным ключом). В таблице у нас 1 628 991 строк и id идут по порядку, а это значит, что мы можем просто перербрать их по одному:
Если кто не понимает, команда работает следующим образом: просматривает построчно таблицу и отправляет stdout в /dev/null, но если команда SELECT проваливается, то выводится текст ошибки (stderr отправляется в консоль) и выводится строка, содержащая ошибку (благодаря ||, которая означает, что у select возникли проблемы (код возврата команды не 0)).
Мне повезло, у меня были созданы индексы по полю id:
А это значит, что нахождение строки с нужным id не должен занимать много времени. В теории должно сработать. Что же, запускаем команду в tmux и идём спать.
К утру я обнаружил, что просмотрено около 90 000 записей, что составляет чуть более 5%. Отличный результат, если сравнивать с предыдущим способом (2%)! Но ждать 20 дней не хотелось…
Попытка 6: SELECT, FROM, WHERE id >= and id <
У заказчика под БД был выделен отличный сервер: двухпроцессорный Intel Xeon E5-2697 v2, в нашем расположении было целых 48 потоков! Нагрузка на сервере была средняя, мы без особых проблем могли забрать около 20-ти потоков. Оперативной памяти тоже было достаточно: аж 384 гигабайт!
Поэтому команду нужно было распараллелить:
Тут можно было написать красивый и элегантный скрипт, но я выбрал наиболее быстрый способ распараллеливания: разбить диапазон 0-1628991 вручную на интервалы по 100 000 записей и запустить отдельно 16 команд вида:
Но это не всё. По идее, подключение к базе данных тоже отнимает какое-то время и системные ресурсы. Подключать 1 628 991 было не очень разумно, согласитесь. Поэтому давайте при одном подключении извлекать 1000 строк вместо одной. В итоге команда преобразилоась в это:
Открываем 16 окон в сессии tmux и запускаем команды:
Через день я получил первые результаты! А именно (значения XXX и ZZZ уже не сохранились):
Это значит, что у нас три строки содержат ошибку. id первой и второй проблемной записи находились между 829 000 и 830 000, id третьей – между 146 000 и 147 000. Далее нам предстояло просто найти точное значение id проблемных записей. Для этого просматриваем наш диапазон с проблемными записями с шагом 1 и идентифицируем id:
Счастливый финал
Мы нашли проблемные строки. Заходим в базу через psql и пробуем их удалить:
К моему удивлению, записи удалились без каких-либо проблем даже без опции zero_damaged_pages.
Затем я подключился к базе, сделал VACUUM FULL (думаю делать было необязательно), и, наконец, успешно снял бекап с помощью pg_dump. Дамп снялся без каких либо ошибок! Проблему удалось решить таким вот тупейшим способом. Радости не было предела, после стольких неудач удалось найти решение!
Благодарности и заключение
Вот такой получился мой первый опыт восстановления реальной базы данных Postgres. Этот опыт я запомню надолго.
Ну и напоследок, хотел бы сказать спасибо компании PostgresPro за переведённую документацию на русский язык и за полностью бесплатные online-курсы, которые очень сильно помогли во время анализа проблемы.
При нарушении целостности файловой системы сервера баз данных PostgreSQL, последний выдает “Ошибка СУБД” 1С, и часто сопровождается текстом, типа “ERROR: invalid page header in block ХХХХХ of relation base/ХХХХХ/ХХХХХ”.
Причиной подобных исключений может служить разрушенная файловая система и нарушение логической целостности всей базы данных, произошедшие в результате некорректного завершения работы ОС.
Выводимую 1С “Ошибка СУБД” на самом деле надо начинать исправлять не в 1С, а с проверки файловой системы. Полный алгоритм восстановления будет приблизительно следующий:
- Исправление ошибок файловой системы;
- Выявление неисправных таблиц СУБД и их ремонт;
- Проверка и исправление ошибок на уровне 1С в конфигураторе.
Если “Ошибка СУБД” в 1С произошла после некорректного завершения работы ОС, начинаем с команд Chkdsk в Windows и fsck в Linux. Это позволит устранить ошибки на уровне файловой системы.
Затем надо выяснить в каких таблицах БД PostgreSQL возникает ошибка “ERROR: invalid page header in block…”. Для этого обращаемся к логам или пытаемся снять дамп базы данных, например подключившись к СУБД утилитой pgAdmin. Если возникает ошибка “Ошибка СУБД” в 1С, наверняка найдется хотя бы 1 испорченная таблица. В моем случае ошибка возникла при дампе public._enum332.
Для того, чтобы восстановить сломанную таблицу, выполним 3 запроса:
Далее снова пытаемся снять дамп базы данных, пока база не выгрузится без ошибок.
Следующим этапом исправления ошибки СУБД в 1С будет Тестирование и исправление базы в конфигураторе 1С. Для этого запускаем испорченную БД в конфигураторе. Через пункт Администрирование – Тестирование и исправление ИБ пробуем восстановить логическую целостность нашей базы. Обратите внимание, на галочки, выбранные на изображении.
При большом количестве ошибок СУБД, 1С потребуется помощь программиста или грамотного пользователя 1С помимо системного администратора, поэтому будьте готовы к привлечению подобных специалистов.
На этом процедуру исправления ошибки PostgreSQL “ERROR: invalid page header in block…” при работе с 1С можно считать законченной, однако стоит отметить несколько пунктов, которые позволят не допустить возникновение ошибки СУБД в 1С:
Читайте также: