Восстановление базы 1С из бэкапа: готовые скрипты для MS SQL и PostgreSQL
Иван Недомолков · Chop etilgan:
Свежая копия рабочей базы нужна чаще, чем кажется: проверить доработку на живых данных, отрепетировать обновление конфигурации, разобрать вчерашнюю ошибку, не трогая прод. Цена пропущенной репетиции хорошо видна в разборе, где база 1С перестала открываться после обновления, а копии не было. И почти всегда между разработчиком и копией стоит один страх: restore, направленный не туда, ложится поверх боевой базы, и отменить это нельзя.
Осторожность этот страх лечит плохо. Лечит скрипт, в котором защита написана до восстановления. Ниже готовые скрипты для обеих СУБД, под которыми живёт 1С, с предохранителями и замером скорости на живом сервере. В конце - как перевести разовое восстановление в ночное задание, чтобы копия обновлялась без вас.
Есть и аварийный повод поднять копию рядом с рабочей: CHECKDB нашёл битые страницы, и надо понять, какие документы из бэкапа вернуть. Как получить их список сверкой двух баз и не откатывать всю базу на вчера, разобрано в статье что пропало в 1С после ошибок CHECKDB. Худший случай, когда восстанавливать штатно уже нечего, потому что шифровальщик испортил и базы, и сетевые бэкапы, разобран отдельно: как собрать базу 1С без ключа из уцелевших страниц.
Сколько это занимает: замер
Цифры с прогона 21.08.2026, локальный MS SQL Server 2022, рабочая база 17,8 ГБ.
| Шаг | Время | Результат |
|---|---|---|
| Бэкап с компрессией | 134 с | файл .bak 3,57 ГБ |
| Восстановление копии | 140 с | база ONLINE, 8 511 таблиц - как в оригинале |
База под 18 гигабайт разворачивается за две с небольшим минуты. На общем сервере, где диски делит прод, будет медленнее, а переносить это число на свою базу нельзя вовсе: на другом стенде логический дамп базы на 23 ГБ поднимался 19 минут 39 секунд, так что своё время восстановления стоит замерить до того, как его спросит бизнес. Ветка PostgreSQL прогонялась отдельно на PostgreSQL 17.9: pg_dump в кастомном формате и pg_restore довезли все таблицы источника без потерь.
MS SQL: сначала спросить бэкап, что у него внутри
Классическая ошибка ручного restore - угаданные логические имена файлов. У базы, которую когда-то переименовывали, логические имена не совпадают с именем базы, и RESTORE с неверным MOVE падает после долгого чтения бэкапа. Угадывать имена незачем - их спрашивают у самого файла:
RESTORE FILELISTONLY
FROM DISK = N'D:\Backup\UT_Prod.bak';
В колонке LogicalName будут имена файлов данных и журнала - они и подставляются в MOVE ниже.
MS SQL: восстановление с предохранителями
-- Восстановление копии рабочей базы на тест.
-- Источник: бэкап UT_Prod. Цель: UT_Test. Сгенерировано 29.08.2026.
DECLARE @target sysname = N'UT_Test';
DECLARE @source sysname = N'UT_Prod';
-- Предохранитель 1: цель не совпадает с источником
IF @target = @source
BEGIN
RAISERROR(N'Цель совпадает с источником. Восстановление остановлено.', 16, 1);
RETURN;
END;
-- Предохранитель 2: цель не служебная база
IF @target IN (N'master', N'model', N'msdb', N'tempdb')
BEGIN
RAISERROR(N'Целью не может быть служебная база.', 16, 1);
RETURN;
END;
RESTORE DATABASE [UT_Test]
FROM DISK = N'D:\Backup\UT_Prod.bak'
WITH MOVE N'UT_Prod' TO N'D:\Data\UT_Test.mdf',
MOVE N'UT_Prod_log' TO N'D:\Data\UT_Test_log.ldf',
REPLACE, STATS = 10;
Про каждый элемент по строке. Шапка-комментарий с датой, источником и целью - через полгода в задании планировщика видно, что и куда льётся. Проверки стоят до RESTORE и падают громко: RAISERROR уровня 16 останавливает скрипт раньше, чем что-либо тронуто. К боевой базе скрипт на запись не обращается вообще - источником служит файл бэкапа, прод при восстановлении только читался в момент снятия .bak. REPLACE нужен при повторном восстановлении поверх прошлой копии.
Предохранители кажутся лишними ровно до первого раза. Проверялось подлогом: на совпадающие имена источника и цели скрипт отвечает ошибкой и до восстановления не доходит. Громкий отказ вместо тихого затирания - единственное поведение, которое стоит принимать от такой защиты.
PostgreSQL: та же схема
# Бэкап рабочей базы в кастомном формате (источник только читается)
pg_dump -Fc -h prod-host -U backup_user ut_prod -f /backup/ut_prod.dump
# Предохранитель: цель не равна источнику
if [ "ut_test" = "ut_prod" ]; then
echo "Цель совпадает с источником, стоп" >&2; exit 1
fi
# Пересоздание тестовой базы и восстановление
dropdb --if-exists ut_test
createdb ut_test
pg_restore -d ut_test --no-owner --jobs=4 /backup/ut_prod.dump
Кастомный формат (-Fc) даёт сжатие и параллельное восстановление через —jobs. Ключ —no-owner избавляет от ошибок владельца, когда роль на тестовом сервере называется иначе, чем на боевом.
Разовое восстановление против расписания
Теперь главное, из-за чего копии протухают. Скрипт выше решает задачу “поднять копию сегодня”. Через месяц тест снова отстанет, и всё повторится: попросить, дождаться, напомнить. Пока восстановление запускает человек, оно случается по большим праздникам - и разработка живёт на данных месячной давности. Чем это оборачивается и как сверить, насколько тест уже разошёлся с продом, - отдельный разбор про отставшую тестовую базу.
Лечится переводом того же скрипта в задание планировщика.
Для MS SQL это задание SQL Server Agent: один шаг типа T-SQL с текстом скрипта восстановления, расписание “ежедневно, 03:00”. Если Agent выключен или у вас Express, где его нет, тот же скрипт запускается через sqlcmd из планировщика Windows:
sqlcmd -S localhost -E -i D:\Scripts\restore_ut_test.sql
Для PostgreSQL - строка cron на пользователя postgres:
0 3 * * * /scripts/refresh_ut_test.sh >> /var/log/refresh_ut_test.log 2>&1
Ночью сервер свободен, окно не мешает никому, а утром в тесте вчерашние данные. Предохранители при этом живут в самом скрипте, и это принципиально: задание крутится месяцами после того, как про него забыли, и защита обязана ехать внутри текста - в голове настроившего она столько не проживёт.
Всю эту сборку - скрипты restore под обе СУБД с автоподстановкой имён через FILELISTONLY, предохранители и генерацию задания по расписанию штатным конструктором - делает наша обработка Тестовая база сама обновляется из свежего прода. Она ничего не выполняет на СУБД сама: собирает готовый текст, который вы читаете и отдаёте администратору, поэтому работает и там, где у разработчика нет прав на SQL.
Три вопроса, которые стоит закрыть до расписания
Куда смотрит строка соединения тестовой базы. Восстановление подменяет содержимое SQL-базы, но информационная база 1С на неё уже смотрит. Проверьте, что тестовая ИБ в кластере привязана именно к целевой SQL-базе, и что в свежеподнятой копии выключены регламентные задания и обмены - иначе копия прода начнёт слать документы наружу как настоящая. Заодно посмотрите, каким логином тестовая ИБ ходит в SQL: если тем же, что рабочая, пароль от прода лежит и в файле кластера тестового сервера, причём в извлекаемом виде. У каких баз кластера это так, показывает аудит паролей СУБД.
Живые данные на тесте. Копия прода несёт реальных контрагентов и зарплаты. Восстановление отвечает за свежесть, за приватность отвечает доступ к тестовому контуру: если тест открыт людям, которым живые данные видеть нельзя, после подъёма копии гоняйте обезличивание отдельным шагом. Какие места базы при этом проверить, чтобы ИИН не остался в реквизите с неожиданным именем, мы собрали в карту персональных данных 1С.
Долгий бэкап - отдельная болезнь. Если снятие .bak растягивается на часы, расписание упрётся в него, и чинить надо сам бэкап: компрессию, диски, схему. Про это есть разбор почему бэкап 1С идёт всю ночь.
Когда полная копия не годится вовсе - база в терабайты, а в тесте жалко терять настройки и наработки - вместо восстановления работает сверка с догрузкой свежего периода, это другой инструмент и другая статья: тестовая база отстала от рабочей.
Нужно поставить обновление копий на поток, а заниматься некогда - напишите нам: настроим бэкап и восстановление по расписанию и проверим, что из этого реально поднимается - это часть обслуживания баз 1С.