Как восстановить базу 1С на PostgreSQL при ошибках «invalid page header» и «row is too big» после сбоя диска?

Системный администратор 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Ситуация, когда из-за аппаратного сбоя жесткого диска база данных 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. Идентификация поврежденной таблицы в контексте 1С

Прежде чем приступать к радикальным мерам, нам необходимо понять, какие данные пострадали. В системе 1С имена таблиц в PostgreSQL выглядят как _accumrgt22959 или _document150. Проанализируем префиксы:

Если ошибка указывает на таблицу _accumrgt (как в нашем примере), нам «повезло». Эти таблицы хранят только рассчитанные итоги для ускорения отчетов. Сами первичные записи хранятся в таблицах _accumreg.

Шаг 2. Очистка поврежденной таблицы и пересчет итогов

Поскольку таблица итогов повреждена на физическом уровне и VACUUM не помогает, самым быстрым и безопасным способом будет ее полная очистка. Разберем этот процесс по шагам.

1. Сначала нам нужно убедиться, что мы работаем именно с таблицей итогов. Для этого можно воспользоваться консолью запросов в 1С или проанализировать структуру в pgAdmin. 2. Выполним команду очистки таблицы в SQL-консоли:


-- Очищаем таблицу, игнорируя поврежденные индексы
TRUNCATE TABLE public._accumrgt22959;

3. После выполнения TRUNCATE таблица станет пустой, и все битые блоки будут удалены на уровне файловой системы. Теперь нам нужно заставить 1С восстановить эти данные из таблиц движений. 4. Откроем базу в режиме Конфигуратора. 5. Перейдем в меню Администрирование — Тестирование и исправление. 6. Выберем пункт «Пересчет итогов». Нажмем «Выполнить».

Важный момент: Просто очистить таблицу в SQL недостаточно, так как 1С будет считать, что остатки нулевые. Только процедура пересчета итогов корректно заполнит таблицу _accumrgt актуальными данными.

Шаг 3. Пересоздание индексов

Если ошибка row is too big возникает при выполнении REINDEX, это может означать, что повреждены не только данные, но и сами индексные файлы. Попробуем радикальный метод пересоздания индексов:

  1. Найдем описание индексов для конкретной таблицы (через pgAdmin или запрос к pg_indexes).
  2. Удалим текущие индексы: DROP INDEX index_name;.
  3. Создадим их заново вручную.

Это часто помогает, если повреждение локализовано в .index файлах, а не в основной таблице (Heap).

Шаг 4. Использование «построчного спасения» данных

Если повреждена основная таблица (например, справочник или документы), и 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) — координаты перед битым блоком

Таким образом, мы можем «перепрыгнуть» через битый блок и продолжить копирование со следующей исправной страницы.

Шаг 5. Восстановление из другой базы (РИБ или копия)

Рассмотрим вариант, предложенный в обсуждении: замена таблиц из вышестоящей базы (в случае распределенной информационной базы — РИБ). Это рабочий метод, но он требует осторожности:

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 пересоздаст их при следующем сканировании.

Резюмируем алгоритм действий при тяжелых повреждениях:

  1. Определяем имя таблицы через логи PostgreSQL.
  2. Если это итоги (_accumrgt) — делаем TRUNCATE и пересчет в 1С.
  3. Если это основные данные — пытаемся выгрузить в .dt файл. Если не выгружается — используем метод ctid или частичное восстановление из бэкапа.
  4. После любых манипуляций в SQL всегда завершаем работу процедурой «Тестирование и исправление» в 1С.

Помните, что работа с параметром zero_damaged_pages = on всегда ведет к потере данных в поврежденных блоках. Это допустимо для таблиц итогов, но требует тщательной проверки для справочников и документов.

← На главную