Ситуация, когда из-за аппаратного сбоя жесткого диска база данных PostgreSQL перестает создавать дампы, а операции VACUUM и REINDEX завершаются критическими ошибками, является одной из самых сложных в практике системного администратора. В этой статье мы подробно разберем, как восстановить работоспособность базы 1С, когда стандартные средства обслуживания Postgres пасуют перед поврежденными данными.
Рассмотрим ситуацию, описанную в теме. После «посыпавшегося» диска система выдает ошибку: invalid page header in block 0 of relation base/16402/18089146. Это прямое указание на то, что физическая структура страницы базы данных нарушена. Заголовок страницы (Page Header) содержит метаданные, необходимые PostgreSQL для понимания того, как читать данные в этой странице. Если заголовок поврежден, СУБД не может определить границы строк.
Попытки исправить ситуацию с помощью параметра zero_damaged_pages = on часто приводят к появлению новых ошибок, таких как index row requires X bytes, maximum size is 8191 или row is too big. Выясним причину этого поведения: когда заголовок зануляется или интерпретируется неверно, PostgreSQL начинает считывать «мусорные» данные как длину строки. В результате СУБД «считает», что одна строка занимает сотни мегабайт, что невозможно при стандартном размере страницы в 8 КБ. Это делает невозможным выполнение VACUUM FULL и pg_dump, так как эти операции требуют полного сканирования таблицы.
Прежде чем приступать к радикальным мерам, нам необходимо понять, какие данные пострадали. В системе 1С имена таблиц в PostgreSQL выглядят как _accumrgt22959 или _document150. Проанализируем префиксы:
Если ошибка указывает на таблицу _accumrgt (как в нашем примере), нам «повезло». Эти таблицы хранят только рассчитанные итоги для ускорения отчетов. Сами первичные записи хранятся в таблицах _accumreg.
Поскольку таблица итогов повреждена на физическом уровне и VACUUM не помогает, самым быстрым и безопасным способом будет ее полная очистка. Разберем этот процесс по шагам.
1. Сначала нам нужно убедиться, что мы работаем именно с таблицей итогов. Для этого можно воспользоваться консолью запросов в 1С или проанализировать структуру в pgAdmin.
2. Выполним команду очистки таблицы в SQL-консоли:
-- Очищаем таблицу, игнорируя поврежденные индексы
TRUNCATE TABLE public._accumrgt22959;
3. После выполнения TRUNCATE таблица станет пустой, и все битые блоки будут удалены на уровне файловой системы. Теперь нам нужно заставить 1С восстановить эти данные из таблиц движений.
4. Откроем базу в режиме Конфигуратора.
5. Перейдем в меню Администрирование — Тестирование и исправление.
6. Выберем пункт «Пересчет итогов». Нажмем «Выполнить».
Важный момент: Просто очистить таблицу в SQL недостаточно, так как 1С будет считать, что остатки нулевые. Только процедура пересчета итогов корректно заполнит таблицу _accumrgt актуальными данными.
Если ошибка row is too big возникает при выполнении REINDEX, это может означать, что повреждены не только данные, но и сами индексные файлы. Попробуем радикальный метод пересоздания индексов:
pgAdmin или запрос к pg_indexes).DROP INDEX index_name;.Это часто помогает, если повреждение локализовано в .index файлах, а не в основной таблице (Heap).
Если повреждена основная таблица (например, справочник или документы), и pg_dump не работает, нам придется выгружать данные по частям. Рассмотрим, как пропустить битые страницы, используя системный столбец ctid.
Столбец ctid представляет собой пару (номер_страницы, номер_строки). Мы можем попытаться скопировать данные в новую таблицу, обходя поврежденные участки. Проанализируем пример логики:
-- Создаем копию структуры таблицы
CREATE TABLE table_backup AS SELECT * FROM original_table WHERE 1=0;
-- Пытаемся копировать данные частями
INSERT INTO table_backup
SELECT * FROM original_table
WHERE ctid < '(X, Y)'; -- Где (X, Y) — координаты перед битым блоком
Таким образом, мы можем «перепрыгнуть» через битый блок и продолжить копирование со следующей исправной страницы.
Рассмотрим вариант, предложенный в обсуждении: замена таблиц из вышестоящей базы (в случае распределенной информационной базы — РИБ). Это рабочий метод, но он требует осторожности:
1. Выясним имя соответствующей таблицы в «здоровой» базе. Помните, что суффиксы (цифры в конце имени) могут отличаться! Для сопоставления имен используйте таблицу DBSchema.
2. Сделаем дамп конкретной таблицы из здоровой базы:
pg_dump -t healthy_table_name -d healthy_db > table_dump.sql.
3. Загрузим этот дамп в поврежденную базу, предварительно удалив там битую таблицу.
4. После такой манипуляции обязательно запустите в Конфигураторе 1С «Тестирование и исправление» с флагом «Проверка логической целостности», так как ссылки (UUID) в таблицах итогов должны соответствовать ссылкам в основных таблицах.
Перенос базы простым копированием каталога data на новый диск, как сделал автор темы, — это крайняя мера. Она переносит проблему «как есть», включая битые файлы _fsm (Free Space Map) и _vm (Visibility Map). Если после переноса VACUUM продолжает падать, попробуйте удалить эти вспомогательные файлы для проблемной таблицы (они имеют те же имена, что и файл таблицы, но с суффиксами). PostgreSQL пересоздаст их при следующем сканировании.
Резюмируем алгоритм действий при тяжелых повреждениях:
_accumrgt) — делаем TRUNCATE и пересчет в 1С..dt файл. Если не выгружается — используем метод ctid или частичное восстановление из бэкапа.Помните, что работа с параметром zero_damaged_pages = on всегда ведет к потере данных в поврежденных блоках. Это допустимо для таблиц итогов, но требует тщательной проверки для справочников и документов.