Есть база 1С, работает на Postgres SQL. В один момент перестал выполняться бэкап. В логах появилась ошибка "ERROR: missing chunk number 0 for toast value 36011983 in pg_toast_44022".
В этой статье расскажу по этапам, как удалось ее победить.
🔥 Для начала важное замечание!
Перед выполнением любых действий на рабочей базе сделайте резервную копию.
Если бэкап не выполняется стандартными способами, то обязательно скопируйте полностью каталог "DATA".
Я буду рассматривать решение вопроса на PostgresSQL for Windows. Каталог data по умолчанию расположен по такому пути: "C:\Program Files\PostgreSQL\11.5-19.1C\data"
🔴 Что произошло?
В один момент Postgres SQL престал выполнять резервное копирование и отваливался с ошибкой, попытался решить проблему следующими способами:
- Тестирование базы средствами СУБД;
- Реиндексация проблемной таблицы средствами СУБД;
- Выгрузка базы средствами 1С;
- Тестирование и исправление средствами 1С;
- Добавление новых объектов метаданных в конфигураторе 1С и реструктуризация БД;
По итогу все время выходит одна и та же ошибка: "ERROR: missing chunk number 0 for toast value 36011983 in pg_toast_44022".
🟢 Решение проблемы!
1. Решил определить в какой конкретно таблице проблема и сопоставить эту таблицу с метаданными 1С. Возможно получиться с ней что-то сделать средствами 1С.
Ошибка ссылается на таблицу pg_toast_44022. Это служебная таблица (тост), нужно определить с какой конкретно таблицей БД она связана.
Для начала зайдем в консоль psql. Откроем Командную строку (cmd.exe) и введем команду: 'psql -U postgres -d BASE', где postgres - имя пользователя СУБД, BASE имя нашей базы. После ввода нужно будет ввести пароль пользователя postgres.
Для определения реальной таблицы выполним команду: 'select 44022::regclass;', где 44022 это суффикс из таблицы pg_toast_44022.
В итоге получили таблицу _commonsettings. Это таблица, где хранятся настройки пользователей 1С. Это уже хорошо.
Попробовал очистить настройки пользователей в 1С, но опять та же ошибка 😡
2. Решил очистить эту таблицу средствами СУБД. В этой таблице не хранятся критичные данные, только пользовательские настройки. Не очень хорошо, но как вариант нужно попробовать.
Выполнил команду полной очистки таблицы: 'delete from _commonsettings;'.
Все прошло хорошо, после этого база заработала. Бекап выполняется, как средствами 1С так и СУБД. Бинго!
3. Решил покопаться и все-таки не очищать всю таблицу, а найти битую запись.
Для начала решил выяснить сколько записей в этой таблице, команда: 'select count(*) from _commonsettings;'. Оказалось не так много, всего — 819.
Далее, попробовал сделать полную выборку: 'select * from _commonsettings;' По итогу опять ошибка.
Хорошо, буду выбирать партиями по 100 записей: 'select * from _commonsettings limit 100;'. Нормально, процесс пошел. Прерывать пролистывание строк можно комбинацией CTRL+C.
Каждый раз увеличивал количество строк и собственно подбором пришел к тому, что битая строка оказалась под номером 441. На ней ошибка, а на 440 все проходит хорошо.
Чтобы удалить конкретную запись нужно как-то ее отобрать по какому-то признаку. Для этого сначала посмотрим за структуру данных, выполним команду: 'select * from _commonsettings limit 1 offset 441;'. Получим одну запись. В данным случае мы получаем запись с номером 440, которая не битая. В команде указано 441, так как нумерация для оператора offset начинается с 0. Если выполнить команду с offset 440 (441 по счету строка, так ка нумерация с 0), выйдет ошибка.
Нас пока это устроит. Если посмотреть на данные в строке, то единственное более менее нормальное поле, по которому можно сделать отбор это "_version", у этого поля обычное значение, которое можно подставить в отбор.
Но теперь нужно, получить значение поля "_version" у битой строки. Выбор данных всех полей для строки не проходит попробую получить только данные поля "_version": 'select _version from _commonsettings limit 1 offset 440;'. Все получилось!
В итоге после проверки всех полей оказалось, что ошибка была в поле "_settingsdata", таблицы "_commonsettings" в строке 441. Не знаю, что там "испортилось", но думаю без этой строки мы проживем. Буду удалять!
Выполняю команду: 'delete from _commonsettings where _version='\\xaab78a1716b220d64abbbfd1b7579914';'. Обратите внимание, значение, которое мы получали выше было с одним слешем "\", а в отборе нужно поставить два "\\" для экранирования.
После этого ошибка везде пропала!
По итогу получилось вычислить таблицу, поле и запись в которой была проблема. И точечно удалить одну запись в таблице.
Смотрите еще статьи по теме: