Архивирование старых данных БД: стратегия и реализация

База данных разрастается, и с каждым днём работать с ней всё сложнее: запросы тормозят, хранилище дорожает, а обслуживание отнимает время. Мы разрабатываем стратегию и реализуем архивирование старых данных, отделяя горячие данные от холодных без простоев и потери производительности. Наша команда берёт на себя весь цикл — от аудита до внедрения и последующей поддержки, обеспечивая надёжное решение, которое масштабируется вместе с вашим бизнесом.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Архивирование старых данных БД: стратегия и реализация

Бэкенд-разработка: Laravel, Node.js, Django, Rails, GoСредний~3-5 дней
Часто задаваемые вопросы

Таблица events с 500 миллионами строк и ростом 2 миллиона в сутки — это проблема, которая становится острее каждый день. SELECT тормозит, VACUUM не успевает, индексы занимают гигабайты. Без архивирования база распухает, блокировки мешают работе, а стоимость хранения на SSD бьёт по бюджету. Мы решаем такие задачи под ключ — реализуем систему архивирования, которая отделяет горячие данные от холодных без простоев и потери производительности. Наш опыт показывает, что правильная стратегия архивирования снижает нагрузку на базу данных на 70% и сокращает стоимость хранения в 2–3 раза.

Какие проблемы решает архивирование старых данных?

Основная боль — деградация производительности. Когда таблица разрастается, даже простые SELECT с индексом тормозят из-за глубины B-tree и фрагментации. VACUUM не успевает чистить мёртвые строки, и autovacuum отстаёт. Рост затрат на хранение — дорогое SSD-хранилище для данных, к которым обращаются раз в год. Блокировки при массовом удалении — DELETE без батчей блокирует таблицу на минуты. Мы решаем это через батчевое архивирование с SKIP LOCKED — параллельные воркеры не конфликтуют.

После архивирования нагрузка на диск снижается на 70%, время SELECT уменьшается в 3–5 раз, а размер базы сокращается в 2 раза.

Стратегии архивирования: сравнение методов

Partition detach — если таблица партиционирована, старые партиции отсоединяются и переносятся в архивную базу или tablespace. Это самый быстрый подход: операция метаданных, без перемещения строк. Partition detach быстрее батчевого INSERT+DELETE в 50 раз для таблиц с миллиардами строк.

INSERT + DELETE батчами — для непартиционированных таблиц. Копируем строки в архивную таблицу батчами, удаляем из основной. Не создаёт длинных транзакций и позволяет контролировать нагрузку.

Логическая реплика — настраиваем publication на основной базе, subscription на архивной, с фильтром по дате. Архив обновляется в реальном времени — подходит для аудита.

Dump + truncate — экспорт в CSV/parquet, удаление из базы. Данные больше не в PostgreSQL/MySQL — только в файловом архиве. Самый дешёвый вариант хранения.

Как выбрать подходящий метод?

Метод Скорость Нагрузка на БД Сложность
Partition detach Высокая Минимальная Средняя
INSERT+DELETE батчами Средняя Умеренная Низкая
Логическая реплика Низкая Минимальная Высокая
Dump+truncate Высокая Высокая Низкая

Как мы реализуем архивирование: пошаговая инструкция

Шаг 1: Анализ структуры и нагрузки

Оцениваем объём, скорость роста, частоту запросов к старым данным. Определяем, какие таблицы можно партиционировать.

Шаг 2: Выбор стратегии

По таблице выше определяем оптимальный метод. Для большинства проектов подходит батчевое копирование с SKIP LOCKED.

Шаг 3: Написание функции с SKIP LOCKED

Используем батчи по 10 000 строк с паузой 0.1 с. Функция archive_old_events переносит строки из public.events в archive.events:

-- Архивная таблица (может быть в отдельной схеме или базе)
CREATE TABLE archive.events (
    LIKE public.events INCLUDING ALL
);

-- Функция архивирования с батчами
CREATE OR REPLACE FUNCTION archive_old_events(
    p_before_date TIMESTAMPTZ,
    p_batch_size INTEGER DEFAULT 10000
) RETURNS TABLE(batches_processed INTEGER, rows_archived BIGINT)
LANGUAGE plpgsql
AS $$
DECLARE
    v_batches INTEGER := 0;
    v_total BIGINT := 0;
    v_moved INTEGER;
BEGIN
    LOOP
        -- Переносим один батч в архив
        WITH moved AS (
            DELETE FROM public.events
            WHERE id IN (
                SELECT id
                FROM public.events
                WHERE created_at < p_before_date
                LIMIT p_batch_size
                FOR UPDATE SKIP LOCKED -- пропускаем заблокированные строки
            )
            RETURNING *
        )
        INSERT INTO archive.events SELECT * FROM moved;

        GET DIAGNOSTICS v_moved = ROW_COUNT;
        EXIT WHEN v_moved = 0;

        v_batches := v_batches + 1;
        v_total := v_total + v_moved;

        -- Пауза между батчами — не перегружаем диск
        PERFORM pg_sleep(0.1);

        -- Прогресс
        RAISE NOTICE 'Batch %: % rows archived (total: %)', v_batches, v_moved, v_total;
    END LOOP;

    RETURN QUERY SELECT v_batches, v_total;
END
$$;

Запуск:

SELECT * FROM archive_old_events('давняя_дата'::timestamptz, 10000); 

Шаг 4: Настройка планировщика

Artisan-команда запускается ежемесячно в 2:00:

// app/Console/Commands/ArchiveOldData.php
class ArchiveOldData extends Command
{
    protected $signature = 'db:archive {--days=365 : Архивировать данные старше N дней}';
    protected $description = 'Archive old records to archive tables';

    public function handle(): int
    {
        $beforeDate = now()->subDays($this->option('days'))->toDateTimeString();
        $this->info("Archiving events before {$beforeDate}...");

        $result = DB::selectOne(
            'SELECT * FROM archive_old_events(?::timestamptz, 5000)',
            [$beforeDate]
        );

        $this->info("Done: {$result->batches_processed} batches, {$result->rows_archived} rows");

        // VACUUM после массового удаления
        DB::statement('VACUUM ANALYZE events');

        return self::SUCCESS;
    }
}
// app/Console/Kernel.php
$schedule->command('db:archive --days=180')
    ->monthlyOn(1, '02:00')
    ->withoutOverlapping()
    ->onFailure(fn() => Notification::route('telegram', config('services.telegram.ops_chat'))
        ->notify(new ArchivingFailedNotification()));

Шаг 5: Мониторинг и VACUUM

После архивации выполняем VACUUM ANALYZE. Настраиваем алерты на ошибки через Telegram.

Шаг 6: Восстановление из архива

Из архивной таблицы — ATTACH PARTITION к основной без копирования. Из CSV-файлов — COPY-загрузка.

Как восстановить данные из архива?

Из архивной таблицы — ATTACH PARTITION к основной таблице без копирования данных. Из CSV-файлов — COPY-загрузка:

# Восстановить данные из CSV-архива обратно в базу
gunzip -c /mnt/archive/events/2024-01/events_2024-01.csv.gz | \
psql -d mydb -c "COPY events FROM STDIN CSV HEADER"

Для долгосрочного хранения используем файловый архив с ротацией.

Что входит в работу

  • Анализ структуры таблиц и нагрузки
  • Проектирование схемы архива (партиционирование, отдельная БД или файлы)
  • Написание функций/скриптов архивации
  • Настройка планировщика и мониторинга
  • Политика хранения с ротацией
  • Сценарий восстановления из архива
  • Документация процесса и обучение команды

Сроки реализации

Этап Срок
Анализ и проектирование 0.5 дня
Реализация функции архивации 1–1.5 дня
Настройка планировщика и мониторинга 0.5 дня
Документация и обучение 0.5 дня
Общий срок 2.5–3.5 дня

Типичные ошибки

  • Забыть про VACUUM после массового удаления — таблица раздувается.
  • Использовать одну транзакцию для всего объёма — рискуем откатом на часы.
  • Не проверять архив перед удалением — потеря данных.
  • Игнорировать SKIP LOCKED — параллельные процессы блокируют друг друга.

Почему стоит доверить архивирование нам

У нас более 10 лет опыта в администрировании PostgreSQL и MySQL. Мы реализовали системы архивирования для проектов с петабайтами данных. Гарантируем, что процесс не затронет основную бизнес-логику и будет полностью автоматизирован. Свяжитесь с нами — мы оценим ваш проект и предложим оптимальное решение. Получите консультацию инженера по производительности БД.

Для получения дополнительной информации обратитесь к официальной документации PostgreSQL. Политика хранения согласовывается с требованиями бизнеса и регулятора (например, GDPR).

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1543
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1396
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1375
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1143
  • Разработка веб-сайта для компании ФИКСПЕР
    Разработка веб-сайта для компании ФИКСПЕР
    1060