Как восстановить одну таблицу PostgreSQL и сохранить новые заказы
В 11:20 исчезла таблица товаров. В 11:27 это заметили. За семь минут приложение успело принять новые заказы, изменить остатки и обновить несколько клиентов. Резервная копия есть, но предложение «вернём всю базу на утро» теперь звучит как исправление одной неприятности с помощью трёх новых.
В такой ситуации основная рабочая база остаётся источником свежих данных. Старое состояние восстанавливают отдельно, извлекают нужные записи и аккуратно возвращают их в действующую систему. Самая сложная часть — определить, что именно возвращать и какие связи восстановить. Команда импорта обычно занимает меньше места, чем список этих решений.
Содержание
Отдельный VPS для восстановления базы
Разверните прошлое состояние PostgreSQL отдельно от рабочей системы. Подберите память и диск под полный размер копии, индексы, архивы и промежуточный экспорт.
Выбрать VPS для восстановленияСначала выясняем масштаб удаления
Словами «удалили таблицу» часто описывают разные события. DELETE удаляет строки, сохраняя структуру. TRUNCATE очищает таблицу иначе и может затронуть связанные объекты в зависимости от команды. DROP TABLE удаляет сам объект; при каскадном удалении могут исчезнуть зависимые ограничения и представления. План восстановления должен соответствовать реальной операции.
Остановите задачу или пользователя, который продолжает ошибочное действие. Сохраните журнал инцидента, время, название базы и схему. По возможности сделайте резервную копию текущего состояния до исправлений: в ней находятся новые заказы и свидетельства того, что произошло. Не запускайте уборку архивов WAL, пока не выяснили, какие из них понадобятся.
Рабочую базу не следует выключать автоматически на весь период исследования. Иногда можно временно остановить только операции с повреждённым каталогом, оставив чтение и другие сервисы. Но решение зависит от связей данных: если приложение продолжает записывать некорректные заказы, ограничение записи окажется необходимым. Это определяет владелец приложения вместе с администратором базы.
Запишите желаемый результат простыми словами: вернуть отсутствующие товары до случайного удаления, не менять цены уже обновлённых позиций и сохранить все новые заказы. Без такого соглашения технически успешный импорт способен восстановить не ту историю бизнеса.
Откуда взять правильное прошлое
Если имеется логическая копия pg_dump, восстановите её в новую пустую базу на отдельном сервере. Для архивного формата сначала посмотрите состав через pg_restore --list. Логический архив допускает выбор объектов, но таблица может зависеть от типов, функций, последовательностей и других сущностей. Поэтому полная отдельная копия часто проще и надёжнее, чем попытка сразу вытащить один объект в неизвестное окружение. Возможности и ограничения перечислены в справке pg_restore.
Если нужен момент непосредственно перед ошибкой, понадобится заранее подготовленная физическая копия и непрерывная цепочка архивов WAL. Восстановление до точки во времени, или PITR, работает на уровне кластера PostgreSQL, а не одной таблицы. Нельзя передать ему имя products и попросить открутить только этот объект. Устройство такого восстановления описано в руководстве PostgreSQL.
Для физического восстановления подберите совместимую основную версию PostgreSQL, расширения, параметры хранения и достаточное место. Исходные архивы сначала скопируйте либо подключите в режиме, исключающем их изменение. Восстановленная машина не должна отправлять письма, принимать пользовательские запросы или подключаться к рабочим очередям.
Точное время ошибки ищите в журналах и обязательно учитывайте часовой пояс. Выбор цели «на минуту раньше» без понимания времени транзакции может дать неполный результат. Если доступна именованная точка восстановления или точный идентификатор нужного события, используйте соответствующий механизм своей системы резервного копирования. После запуска проверьте данные, а не только сообщение об успешном завершении восстановления.
Отдельный VPS становится рабочим столом восстановления
Для небольшой логической копии можно рассматривать MAATRIX Heka Standard с 8 GB RAM. Но конфигурацию определяет прежде всего объём базы вместе с индексами, временными файлами и архивами. Копию базы на 150 GB нельзя бездумно помещать на диск 160 GB: свободное пространство необходимо и восстановлению, и последующим операциям.
Большой базе может понадобиться более вместительный тариф или другая конфигурация. Перед заказом посчитайте размещение отдельно: архивы, развёрнутые данные, промежуточный экспорт и запас. Быстрая машина с маленьким диском остановится так же уверенно, как медленная, только раньше сообщит об этом.
Доступ к временному VPS MAATRIX ограничьте администраторами восстановления. После работы удалите копии по принятому в компании порядку. На таком сервере находится полноценная история рабочей базы, даже если использовать из неё собираются всего одну таблицу.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
АРЕНДОВАТЬ СЕРВЕРСравниваем структуру до переноса строк
На восстановленной копии изучите таблицу: столбцы, типы, значения по умолчанию, ограничения, индексы, триггеры и права. Сравните их с миграциями приложения и текущей схемой. Между датой резервной копии и сегодняшним днём разработчики могли добавить обязательное поле или изменить смысл статуса.
Если объект полностью удалён, структуру в рабочей базе воссоздают по согласованной миграции. Не стоит запускать весь старый дамп поверх действующей системы с параметром очистки. Такой запуск может удалить исправные объекты. Для изучения DDL допустим отдельный экспорт схемы таблицы из восстановленной копии:
pg_dump --dbname=recovery_copy --schema-only --table=public.products \
--no-owner --no-privileges --file=products-schema.sql
Здесь recovery_copy и public.products — учебные имена. Файл сначала читают и сопоставляют с текущими миграциями. Отдельный экспорт таблицы не обещает включить все внешние зависимости; это отмечено в документации pg_dump. После DROP ... CASCADE особенно внимательно восстанавливают исчезнувшие связи из других таблиц.
Если структура сохранилась, сравните набор старых и новых строк. Отсутствующий идентификатор ещё не доказывает случайное удаление: часть товаров могли снять с продажи намеренно. Нужен список записей, которые действительно следует вернуть, подтверждённый журналами или ответственным сотрудником.
Переносим через промежуточную таблицу
Разберём небольшой пример каталога с полями id, sku, name, price. У настоящего магазина список будет другим. Из восстановленной копии выгружаем только необходимые столбцы. Команда ниже выполняется внутри psql, подключённого именно к восстановленной базе:
\copy public.products(id, sku, name, price) TO 'products-before.csv' WITH (FORMAT csv, HEADER true)
Клиентская команда \copy работает с файлом на машине, где запущен psql; это отличается от серверной команды COPY. Подробности есть в справке psql. Передавайте экспорт по защищённому каналу и не помещайте его в публичную папку сайта.
Сначала на тестовой копии актуальной базы создайте отдельную схему для восстановления и промежуточную таблицу с явно указанными типами. Импортируйте CSV туда. Благодаря этому старые значения можно сравнивать с новыми, не меняя рабочий каталог:
CREATE SCHEMA recovery;
CREATE TABLE recovery.products_before (
id bigint PRIMARY KEY,
sku text NOT NULL,
name text NOT NULL,
price numeric(12,2) NOT NULL
);
\copy recovery.products_before(id, sku, name, price) FROM 'products-before.csv' WITH (FORMAT csv, HEADER true)
Пример предполагает простые типы и отсутствие дополнительных обязательных полей. Если схема recovery уже существует, сначала выясните её назначение: не удаляйте её ради удобства. Для реального проекта подготовьте отдельное уникальное имя промежуточной таблицы.
Сравнение выполняйте не только по первичному ключу. Проверьте артикулы, связанные категории, валюту и признаки удаления. Старый id мог быть использован в ошибочном исправлении, а тот же sku — появиться под другим номером. Такие конфликты требуют решения, а не команды «игнорировать все ошибки».
Возвращаем согласованный набор и сохраняем новые данные
Подготовьте явный перечень идентификаторов для возврата. На тестовой актуальной копии выполните вставку с перечислением столбцов, а не SELECT *. Новые записи, уже существующие в рабочей таблице, не должны автоматически перезаписываться старыми значениями. Если требуется восстановить отдельное поле, это другая операция с собственным условием отбора.
Первую репетицию проведите в транзакции с завершением ROLLBACK. Посмотрите количество затронутых строк и возвращаемые идентификаторы, проверьте ограничения. Учтите, что внешние действия из триггеров или подключённых систем не всегда отменяются вместе с SQL-транзакцией; поэтому репетиция проводится в изолированном окружении.
Перед применением к рабочей базе сохраните новую актуальную копию затрагиваемых объектов и согласуйте короткое окно изменения. Остановите конкурирующие операции над каталогом либо предусмотрите подходящий механизм блокировки. Иначе между сравнением и вставкой могут появиться новые данные, о которых план восстановления не знает.
После возврата проверьте последовательности и identity-поля, чтобы следующая обычная вставка не столкнулась с восстановленным идентификатором. Настраивать их следует с учётом действующих значений и параллельной записи; слепое уменьшение счётчика до максимума старого архива опасно. Затем обновите статистику таблицы штатным ANALYZE и оцените запросы приложения.
Проверяем результат на языке магазина
Сверьте количество восстановленных позиций, несколько конкретных артикулов, связи с заказами и актуальные цены. Откройте товар через приложение, проведите тест разрешённого рабочего действия и убедитесь, что новые заказы после инцидента остались на месте. Если используются поисковый индекс и кеш, обновите затронутые записи управляемо: они могли сохранить сведения об отсутствии товаров.
Промежуточные таблицы и экспорт храните до завершения проверки по согласованному сроку, затем уберите. В журнале восстановления оставьте время, источник копии, критерий отбора и точный набор изменений. Эта запись позволит объяснить результат без повторного расследования.
После инцидента стоит проверить саму систему бэкапов: достаточна ли частота, непрерывно ли сохраняется WAL, известно ли время восстановления и есть ли подходящая площадка. Возможность вернуть отдельные данные рождается из хорошей полной копии и аккуратного сравнения. Волшебной кнопки «отменить только плохое» у базы нет — зато есть последовательность действий, при которой исправление не стирает сегодняшний рабочий день.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США и РФ. Оплата картой РФ и по СБП.
АРЕНДОВАТЬ СЕРВЕРОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →