Хранение временных рядов: чек-лист перед продакшеном
Таблица с метриками может быстро вырасти в хранилище, которое тормозит запросы и мешает удалять старые данные. Проверьте формат времени, индексы, партиции, ретеншн и восстановление — до того, как поток событий станет боевой нагрузкой.

Хранилище временных рядов часто отлично работает на тестовом объёме, а в продакшене начинает дорого индексировать новые данные, медленно отдавать историю и не успевать удалять устаревшее. Ниже — чек-лист для такой проверки на примере PostgreSQL 16: что решить до запуска, какие варианты хранения сравнить и что измерять вместо того, чтобы гадать о будущей нагрузке.
Сначала зафиксируйте форму данных
Временной ряд — не просто таблица с колонкой даты. Важно заранее понять, кто и как записывает события, как они запрашиваются и когда перестают быть нужны. Если эти правила оставить «на потом», схема будет закреплять случайные решения: например, локальное время одного сервиса и UTC другого.
- Определите время события. Выберите одну временную зону для хранения и зафиксируйте, означает ли метка время возникновения события или его приёма системой. В PostgreSQL для временных меток с часовым поясом используют тип
timestamptz; приложение всё равно должно последовательно передавать время. - Оцените опоздания и повторы. Уточните, могут ли события приходить задним числом и отправлять ли источники дубликаты. Если повторная запись возможна, продумайте идентификатор события и способ обнаруживать повторы.
- Запишите реальные запросы. Например: выборка метрики за последние сутки по устройству, агрегат за месяц по региону, поиск одного события по идентификатору. Для каждого запроса укажите фильтры, сортировку и объём результата.
- Посчитайте срок хранения. Разделите данные на те, что нужны для оперативных запросов, архивной аналитики и тех, которые можно удалить. Не смешивайте срок хранения с периодом резервного копирования.
- Проверьте размер события. Включите в оценку не только полезную нагрузку, но и индексы, служебные данные и резервные копии. Точную долю накладных расходов лучше измерить на репрезентативной выборке.
Термин: кардинальность — число различных значений поля. Если в метриках есть уникальный идентификатор запроса или пользователя, поле может иметь высокую кардинальность. Индексировать каждую такую размерность без проверки — значит увеличивать цену записи и хранения.
Выберите схему хранения по запросам
Для начала сравните три варианта: обычную таблицу PostgreSQL 16, её секционирование по времени и TimescaleDB с гипертаблицей. Это не рейтинг: цена решения зависит от объёма, характера запросов, опыта команды и того, как устроена эксплуатация.
| Подход | Что выигрываете | Чем платите | Когда рассматривать |
|---|---|---|---|
| Обычная таблица PostgreSQL 16 | Простая схема и минимум отдельных механизмов обслуживания. | С ростом таблицы нужно отдельно проверять стоимость запросов, индексов и очистки старых данных. | Небольшой объём, умеренная скорость записи, понятный срок хранения. |
| Секционирование PostgreSQL 16 по времени | Запросы с ограничением по времени могут отсекать ненужные секции; старые данные можно обслуживать секциями, а не удалять по одной строке. | Нужно планировать создание и обслуживание секций. Запросы без условия по ключу секционирования могут не получить ожидаемого выигрыша. Ограничения уникальности должны учитывать ключ секционирования. | Большая таблица с временными запросами и понятной политикой удаления истории. |
| TimescaleDB hypertable | Временные данные распределяются по внутренним временным чанкам через расширение для PostgreSQL. | Появляется зависимость от расширения и его совместимости с вашей версией PostgreSQL и процедурами эксплуатации. | Команде нужны специализированные возможности TimescaleDB и она готова сопровождать расширение. |
Секционирование в PostgreSQL не ускоряет автоматически любой запрос. В PostgreSQL 16 планировщик может исключать секции, которые не подходят под фильтр по ключу секционирования. Поэтому проверьте реальные планы запросов, а не только наличие секций. Уникальные ограничения на секционированной таблице должны включать все столбцы ключа секционирования — это влияет на выбор первичного ключа и способ защиты от дубликатов.
Хранилище готово не тогда, когда запись работает на тесте, а когда команда знает, сколько стоит один день данных, как удалить лишнее и как восстановить систему после сбоя.
Чек-лист перед запуском
- Смоделируйте типичную нагрузку. Подготовьте данные с реалистичными метками времени, разбросом размеров и долей поздних событий. Проверьте одновременно запись и основные запросы. Результат: вы знаете время ответа при работающей записи, а не только на пустой базе.
- Подберите индексы под запросы. Начните с фильтров и порядка сортировки, которые действительно использует приложение. Каждый индекс ускоряет подходящие чтения, но занимает место и добавляет работу при записи. Результат: планы запросов показывают, что база обрабатывает нужный временной диапазон, а запись остаётся в допустимых для сервиса пределах.
- Спланируйте секции или чанки. Если выбрали секционирование, решите, как заранее создавать будущие секции и что делать, если новые данные пришли за пределами подготовленного диапазона. Для TimescaleDB проверьте правила работы гипертаблиц в документации именно той версии расширения, которую собираетесь ставить. Результат: поступление данных не зависит от ручного вмешательства в неудобный момент.
- Опишите ретеншн. Укажите срок хранения, ответственного и процедуру удаления. При секционировании удаление целой старой секции может быть удобнее массового удаления строк, но границы секций должны совпадать с политикой хранения. Результат: проверено, что удаление действительно освобождает место по плану, а не создаёт неожиданную нагрузку.
- Проверьте поздние и повторные события. Прогоните тест с записями за прошлые интервалы и с дубликатами. Результат: понятны поведение схемы, стоимость исправлений и последствия повторной доставки.
- Испытайте резервное копирование и восстановление. Восстановите базу или выбранную копию на отдельном контуре. Если используете расширение, включите в проверку его наличие и совместимость. Результат: команда знает фактическое время восстановления и проверила доступность нужных данных.
- Настройте наблюдение. Следите за задержкой записи, p95/p99 запросов, ростом объёма таблиц и индексов, размером WAL, отставанием реплики и временем обслуживания секций. Результат: для каждого показателя определён порог реакции, а не только график на дашборде.
Что ломается и когда выбирать другой подход
Типичный провал — выбрать секционирование только потому, что таблица большая. Если приложение почти всегда ищет запись по идентификатору и не ограничивает запрос временем, секции сами по себе могут не помочь. Другой риск — делать секции слишком мелкими: ими становится сложнее управлять, а выигрыш в запросах ещё нужно подтвердить замерами.
Обычную таблицу выбирайте, если измерения показывают, что её хватает и удаление истории не мешает работе. Секционирование PostgreSQL 16 оправдано, когда запросы регулярно ограничивают диапазон времени и нужно управлять большими порциями старых данных. TimescaleDB имеет смысл, если нужные возможности расширения важны для проекта и команда готова следить за его версиями, обновлениями и восстановлением.
Если в продакшене запросы внезапно стали медленнее, не начинайте с перестройки всей схемы. Снимите планы проблемных запросов, проверьте, применяются ли временные фильтры, и сопоставьте задержки с объёмом новых данных, индексами и обслуживанием секций. Причина может быть не в формате хранения, а в запросе, который читает слишком широкий диапазон.
Что делать дальше
Возьмите три самых частых запроса и один сценарий удаления старых данных. На копии производственного объёма сравните варианты по задержке записи, p95/p99 чтения, росту места и времени восстановления. Зафиксируйте, при каких условиях выбранная схема перестаёт укладываться в требования. Для PostgreSQL 16 сверяйте детали секционирования с официальной документацией; для TimescaleDB — с документацией конкретной версии расширения. Инвалидация агрегатов и построение аналитических витрин — отдельная задача, здесь рассматривается именно готовность слоя хранения.
Тендерный специалист 44-ФЗ / 223-ФЗ: Разбор PDF-документации закупки, поиск «заточек» под поставщика, чек-лист заявки.
Спросить за 20 ₽Источники: PostgreSQL 16: декларативное секционирование, TimescaleDB: гипертаблицы
Частые вопросы
Нужно ли секционировать таблицу сразу, пока данных мало?
Как выбрать размер секции по времени?
Можно ли хранить время в локальном часовом поясе?
Что делать, если данные приходят с опозданием?
Что если у меня не PostgreSQL 16?
Какие показатели смотреть после запуска?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.