02 дек. 2025 г.·7 мин

Партиционирование PostgreSQL для таблиц событий в аудит‑логах

Партиционирование PostgreSQL для таблиц событий: когда это оправдано, как выбрать ключ партиционирования и как это влияет на фильтры в админ‑панели и хранение.

Партиционирование PostgreSQL для таблиц событий в аудит‑логах

Почему таблицы событий и аудита становятся проблемой

Таблицы событий и таблицы аудита похожи внешне, но существуют по разным причинам.

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

Обе растут быстро, потому что по факту это append‑only: строки редко удаляются по одной, и новые строки приходят каждую минуту. Даже небольшой продукт может генерировать миллионы строк логов за недели, если учитывать фоновые задания и интеграции.

Боль проявляется в ежедневной работе. В админ‑панелях нужны быстрые фильтры вроде «ошибки за вчера» или «действия этого пользователя». По мере роста таблицы эти простые экраны начинают тормозить.

Обычно сначала заметны несколько симптомов:

  • Фильтры занимают секунды (или тайм аут), даже при узком диапазоне дат.
  • Индексы растут настолько, что вставки замедляются, а затраты на хранение увеличиваются.
  • VACUUM и autovacuum занимают больше времени, начинается видимое обслуживание.
  • Политика хранения становится рискованной: удаление старых строк медленное и создаёт блоут.

Партиционирование — один из способов справиться с этим. Проще говоря, оно разбивает одну большую таблицу на множество меньших таблиц (партиций) под одним логическим именем. PostgreSQL направляет каждую новую строку в нужную партицию по правилу, обычно по времени.

Именно поэтому команды рассматривают партиционирование PostgreSQL для таблиц событий: оно позволяет держать недавние данные в небольших кусках, чтобы PostgreSQL мог пропустить целые партиции, когда запросу нужна только временная часть.

Партиционирование — это не волшебная кнопка скорости. Оно сильно помогает для запросов типа «последние 7 дней» и упрощает хранение (удаление старых партиций быстро). Но оно может и добавить проблем:

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

Если админ‑панель сильно опирается на фильтры по дате и предсказуемые правила хранения, партиционирование может дать реальную выгоду. Если же большинство запросов — «все действия пользователя X за всю историю», это может создать головную боль, если вы не спроектируете UI и индексы должным образом.

Типичные шаблоны доступа для логов и аудитов

Таблицы событий и аудита растут в одном направлении: вверх. В них идёт постоянный поток вставок и почти нет обновлений. Большинство строк записывается один раз, а затем читается позже в поддержке, разборе инцидентов или проверках на соответствие.

Эта «append‑only» форма важна. Производительность записи — постоянная забота, потому что вставки идут весь день, а чтение важно всплесками (когда поддержка или операторы нуждаются в быстрых ответах).

Большинство чтений — это фильтры, а не случайные обращения. В админ‑панели обычно начинают с широкого запроса (последние 24 часа), затем сужают по пользователю, сущности или типу действия.

Распространённые фильтры включают:

  • Временной диапазон
  • Актор (user ID, service account, IP‑адрес)
  • Цель (тип сущности + ID, например Order #1234)
  • Тип действия (created, updated, deleted, login failed)
  • Статус или уровень серьёзности (success/error)

Временной диапазон — естественный «первичный отбор», потому что он почти всегда присутствует. Это ключевое понимание партиционирования PostgreSQL для таблиц событий: многие запросы хотят временной срез, а всё остальное — второй фильтр внутри этого среза.

Хранение — другая постоянная вещь. Логи редко хранятся вечно. Команды часто держат подробные события 30 или 90 дней, затем удаляют или архивируют. Аудит‑логи могут требовать более длительного хранения (365 дней и больше), но даже тогда нужен предсказуемый способ удаления старых данных без блокировки базы.

Аудит сопровождается дополнительными ожиданиями. Обычно нужна неизменяемая история, каждая запись должна быть трассируемой (кто/что/когда плюс контекст запроса или сессии), и доступ должен быть контролируемым (не всем доступна безопасность‑информация).

Эти шаблоны напрямую влияют на дизайн UI. Фильтры, которые люди ожидают по умолчанию — выбор даты, селектор пользователей, поиск по сущности, выпадающий список действий — это те же поля, которые ваши таблицы и индексы должны поддерживать, если вы хотите, чтобы админ‑опыт оставался быстрым по мере роста объёма.

Как понять, стоит ли партиционировать

Партиционирование не является универсальной практикой для аудиторских логов. Оно окупается, когда одна таблица становится настолько большой, что повседневные запросы и рутинное обслуживание начинают конфликтовать.

Простая ориентировка по размеру: когда таблица достигает десятков миллионов строк, стоит замерить показатели. Когда таблица и её индексы занимают десятки гигабайт, даже «простые» поиски по диапазону дат могут стать медленными или непредсказуемыми, потому что читается больше страниц с диска и поддержание индексов дорого.

Самый заметный сигнал по запросам — когда вы регулярно запрашиваете небольшой временной срез (последний день, неделя), но PostgreSQL всё равно обращается к большой части таблицы. Это видно как медленные экраны «последней активности» или аудиты, отфильтрованные по дате плюс пользователь, тип действия или ID сущности. Если планы запросов показывают большие сканирования или постоянные буферные чтения, вы платите за данные, которые не собирались читать.

Сигналы по обслуживанию не менее важны:

  • VACUUM и autovacuum стали занимать намного больше времени.
  • Autovacuum не успевает, и накапливается dead tuples (bloat).
  • Индексы растут быстрее, чем ожидалось, особенно многоколонные.
  • Конкуренция за блокировки становится заметной, когда обслуживание пересекается с трафиком.

Операционные затраты — это медленное подтекание, которое подталкивает команды к партиционированию. Резервные копии и восстановление замедляются, хранение растёт, а задачи удержания становятся дорогими, потому что большие DELETE создают блоут и дополнительную работу VACUUM.

Если ваши основные цели — чистая политика хранения и быстрые запросы по «недавнему периоду», партиционирование обычно стоит рассмотреть серьёзно. Если таблица умеренная и запросы уже быстрые при правильных индексах, партиционирование добавит сложности без очевидной выгоды.

Варианты партиционирования, подходящие для событий и аудита

Для большинства данных событий и аудита самый простой выбор — диапазонное (range) партиционирование по времени. Логи приходят в порядке времени, запросы часто фокусируются на «последних 24 часах» или «последних 30 днях», а хранение обычно основано на времени. С временными партициями удаление старых данных может свестись к простому удалению старой партиции вместо долгого DELETE, создающего блоут.

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

Есть и другие стили партиционирования, но они реже подходят для логов и аудита:

  • List (по тенанту/клиенту) может подойти, если у вас небольшое число очень больших арендаторов и запросы обычно ограничиваются одним тенантом. Но при сотнях или тысячах арендаторов это становится болезненным.
  • Hash (равномерное распределение записи) полезен, когда нет временных запросов и нужно равномерно распределить записи. Для аудита это реже, так как усложняет хранение и просмотр по времени.
  • Субпартиционирование (время + тенант) мощно, но быстро усложняет систему. Это в основном для очень высоких нагрузок с жёсткой изоляцией тенантов.

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

Практический пример: если команда админов проверяет неудачные входы каждое утро и фильтрует по последним 7 дням, суточные или недельные партиции означают, что запрос коснётся только самых свежих партиций. PostgreSQL сможет игнорировать остальные.

Независимо от подхода, запланируйте рутинные задачи: создание будущих партиций, обработку поздних событий и определение поведения на границах (конец дня, конец месяца). Партиционирование окупается, когда эти процедуры остаются простыми.

Как выбрать правильный ключ партиционирования

Генерируйте реальный исходный код
Используйте сгенерированные Go и Vue приложения, когда нужен чистый код, который можно развернуть где угодно.
Создать проект

Хороший ключ партиционирования соответствует тому, как вы читаете таблицу, а не тому, как данные выглядят в диаграмме.

Для логов и аудита начните с вашей админ‑панели: какой фильтр люди используют первым, почти всегда? Для большинства команд это временной диапазон (последние 24 часа, последние 7 дней, произвольные даты). Если это про вас, партиционирование по времени даёт самый предсказуемый выигрыш, потому что PostgreSQL может пропустить целые партиции вне выбранного диапазона.

Рассматривайте ключ как долгосрочное обещание. Вы оптимизируете под запросы, которые будут выполняться годами.

Начните с «первого фильтра», который используют люди

Большинство админ‑экранов следуют шаблону: временной диапазон плюс опционально пользователь, действие, статус или ресурс. Партиционируйте по тому, что сужает результаты рано и стабильно.

Короткая проверка реальности:

  • Если вид по умолчанию — «недавние события», партиционируйте по временной метке.
  • Если вид по умолчанию — «события для одного тенанта/аккаунта», tenant_id может иметь смысл, но только если у вас несколько очень больших тенантов.
  • Если первый шаг всегда «выбрать пользователя», user_id звучит заманчиво, но обычно приводит к слишком большому числу партиций.

Избегайте ключей с высокой кардинальностью

Партиционирование лучше работает, когда каждая партиция — осмысленный кусок данных. Ключи вроде user_id, session_id, request_id или device_id могут породить тысячи или миллионы партиций. Это увеличивает накладные метаданные, усложняет обслуживание и часто замедляет планирование.

Временные партиции держат количество партиций предсказуемым: вы выбираете дневные, недельные или месячные в зависимости от объёма. Слишком мало партиций (по году) мало помогает. Слишком много (по часам) быстро добавляет накладные расходы.

Выберите правильную временную метку: created_at против occurred_at

Будьте явны, что значит «время»:

  • occurred_at: когда событие произошло в продукте.
  • created_at: когда оно записано в базе.

Для аудита «occurred_at» часто важен. Но задержки доставки (оффлайн‑клиенты, повторы, очереди) означают, что occurred_at может приходить позже. Если поздние записи часты, партиционирование по created_at и индексирование occurred_at для фильтрации может быть более стабильным в эксплуатации. Другой вариант — чёткая политика дорефиллинга и принятие того, что старые партиции иногда будут получать поздние события.

Также решите, как хранить время. Используйте единый тип (часто timestamptz) и держите UTC как эталон. Форматируйте под часовой пояс пользователя в UI. Это сохраняет границы партиций стабильными и избегает сюрпризов с переходом на летнее/зимнее время.

Шаг за шагом: план и выкатывание партиционирования

Проектируйте таблицы аудита визуально
Спроектируйте схему событий и ограничения визуально, до того как таблица достигнет миллионов строк.
Начать создание

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

Практический план выката

  1. Выберите размер партиции под объём. Месячные партиции обычно подходят при сотнях тысяч строк в месяц. Если вставок десятки миллионов в месяц, недельные или суточные партиции держат индексы и работу VACUUM в пределах.

  2. Спроектируйте ключи и ограничения для партиционированных таблиц. В PostgreSQL уникальное ограничение должно включать ключ партиционирования (или контролироваться иначе). Обычный паттерн — (created_at, id), где id генерируется, а created_at — ключ партиции. Это предотвращает сюрпризы, когда окажется, что ожидаемое ограничение невозможно.

  3. Создавайте будущие партиции до того, как они понадобятся. Не ждите, пока вставки начнут падать из‑за отсутствия подходящей партиции. Решите, на какой срок вперёд их создавать (например, 2–3 месяца) и автоматизируйте это.

  4. Держите индексы на партициях небольшими и намеренными. Партиционирование не делает индексы бесплатными. Большинству таблиц событий нужен ключ партиции плюс один‑два индекса, соответствующих реальным фильтрам админов, например actor_id, entity_id или event_type. Откажитесь от «на всякий случай» индексов. Их можно добавить в новые партиции и бэкапить старые по мере надобности.

  5. Планируйте хранение вокруг удаления партиций, а не удаления строк. Если вы храните 180 дней, удаление старой партиции быстро и избегает долгих DELETE и блоута. Запишите правило хранения, кто его выполняет и как проверять результат.

Небольшой пример

Если ваша таблица аудита получает 5 миллионов строк в неделю, недельные партиции по created_at — разумная стартовая точка. Создавайте партиции на 8 недель вперёд и держите по две индекса на партицию: по actor_id и по entity_id. Когда срок хранения истекает, удаляйте самую старую недельную партицию вместо удаления миллионов строк.

Если вы строите внутренние инструменты в AppMaster, полезно заранее решить ключ партиционирования и ограничения, чтобы модель данных и сгенерированный код следовали этим допущениям с самого начала.

Что меняет партиционирование для фильтров в админ‑панели

После партиционирования лог‑таблицы фильтры в админ‑панели перестают быть «просто UI». Они становятся главным фактором, решающим, коснётся ли запрос нескольких партиций или просканирует месяцы данных.

Самый большой практический сдвиг: время уже не может быть опциональным. Если пользователи могут запустить неограниченный поиск (без диапазона дат, просто «покажи всё для пользователя X»), PostgreSQL может проверить каждую партицию. Даже если каждая проверка быстрая, открытие множества партиций даёт накладные расходы и страницу начинает «торчать».

Правило, которое хорошо работает: требуйте временной диапазон для поиска по логам и аудиту и по умолчанию ставьте разумный интервал (например, последние 24 часа). Если кому‑то действительно нужно «всё время», делайте это осознанным выбором с предупреждением о замедлении.

Делайте фильтры совместимыми с pruning

Отбрасывание партиций помогает только когда в WHERE есть ключ партиционирования в форме, которую PostgreSQL может использовать. Фильтры типа created_at BETWEEN X AND Y отбрасывают чётко. Шаблоны, которые часто ломают pruning: приведение времени к дате, обёртывание колонки в функции или фильтрация по другому времени, нежели ключ партиции.

Внутри каждой партиции индексы должны соответствовать тому, как люди реально фильтруют. На практике важны комбинации «время + одно условие»: тенант/воркспейс, пользователь, действие/тип, ID сущности или статус.

Сортировка и пагинация: держите глубину небольшой

Партиционирование не решит само по себе проблемы медленной пагинации. Если админ‑панель сортирует по новейшим и пользователи прыгают на страницу 5000, глубокий OFFSET всё равно заставит PostgreSQL просмотреть множество строк.

Курсорная пагинация работает лучше для логов: «загрузить события до этого timestamp/id». Она заставляет базу использовать индексы вместо пропуска огромных смещений.

Шаблоны предустановок тоже помогают. Несколько опций обычно достаточно: последние 24 часа, последние 7 дней, сегодня, вчера, произвольный диапазон. Предустановки уменьшают случайные «просканировать всё» запросы и делают админ‑опыт предсказуемее.

Распространённые ошибки и ловушки

Создайте быстрые экраны логов
Создайте просмотрщик логов с обязательными временными фильтрами и быстрыми запросами с самого начала.
Попробовать AppMaster

Большинство проектов по партиционированию терпят неудачу по простым причинам: партиционирование работает, но запросы и UI не согласованы с ним. Чтобы партиционирование окупилось, проектируйте его вокруг реальных фильтров и правил хранения.

1) Партиционирование по неправильному временному столбцу

Отбрасывание партиций происходит только когда WHERE соответствует ключу партиционирования. Частая ошибка — партиционировать по created_at, а в админке фильтровать по event_time (или наоборот). Если поддержка всегда спрашивает «что было между 10:00 и 10:15», а таблица партиционирована по времени приёма, вы всё равно можете затронуть больше данных, чем ожидали.

2) Создание слишком большого числа мелких партиций

Почасовые (или меньшие) партиции аккуратно выглядят, но добавляют накладные расходы: больше объектов, сложность планировщика запросов и риск пропущенных индексов или несоответствия прав. Если нет экстремально высокой нагрузки на запись и строгого требования по хранению, суточные или месячные партиции проще в эксплуатации.

3) Ожидание глобальной уникальности как прежде

У партиционированных таблиц есть ограничения: некоторые уникальные индексы должны включать ключ партиционирования, иначе PostgreSQL не сможет их обеспечить глобально. Это часто удивляет команды, ожидающие, что event_id останется уникальным по всей истории. Если нужен уникальный идентификатор, используйте UUID и обеспечьте уникальность на уровне приложения или делайте составную уникальность с ключом партиции.

4) Разрешать UI запускать широкие поиски

Админ‑панели часто поставляются с поисковой строкой «дружелюбной» по умолчанию, которая выполняется без фильтров. Для партиционированной лог‑таблицы это может означать сканирование всех партиций.

Поиск по свободному тексту по полезным полям особенно рискован. Введите ограждения: требуйте временной диапазон, ограничьте дефолтный интервал и сделайте «вся история» осознанным выбором.

5) Отсутствие плана хранения (и плана по партициям)

Партиционирование не решает само по себе вопросы хранения. Без политики вы получите кучу старых партиций, беспорядок в хранении и замедление обслуживания.

Простой набор правил обычно это предотвращает: определите, как долго хранятся необработанные события, автоматизируйте создание будущих партиций и удаление старых, применяйте индексы последовательно, мониторьте количество и даты партиций и тестируйте самые медленные фильтры админки на реалистичных объёмах данных.

Быстрая чек‑лист перед принятием решения

Масштабируйте внутренние инструменты уверенно
Создавайте внутренние инструменты, которые остаются отзывчивыми, когда растут логи, задания и вебхуки.
Создать с AppMaster

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

Если ваша основная боль — тайм‑ауты админ‑страниц при открытии «Последние 24 часа» или «На этой неделе», вы близки к хорошему кейсу. Если большинство запросов — «user ID по всей истории», партиционирование может помочь меньше, если вы не измените поведение UI.

Короткий чек‑лист, который помогает остаться честными:

  • Временной диапазон — фильтр по умолчанию. Большинство админ‑запросов включает явное окно (from/to). Если часто встречаются открытые поиски, выгода от pruning меньше.
  • Хранение реализуется удалением партиций, а не DELETE. Вы готовы удалять старые партиции и имеете правило, сколько хранится данных.
  • Число партиций остаётся разумным. Оцените число партиций в год (суточные, недельные, месячные). Слишком много мелких партиций увеличивает накладные расходы. Слишком мало — снижает преимущество.
  • Индексы соответствуют реальным фильтрам. Помимо ключа партиционирования, нужны правильные индексы на партициях для частых фильтров и порядка сортировки.
  • Партиции создаются автоматически и мониторятся. Есть задача, создающая будущие партиции, и вы знаете, когда она падает.

Практический тест: посмотрите три фильтра, которые чаще всего используют поддержка или операторы. Если два из них обычно удовлетворяются «временной диапазон + одно условие», партиционирование PostgreSQL для таблиц событий часто стоит рассмотреть всерьёз.

Реалистичный пример и практические следующие шаги

Команда поддержки держит два экрана открытыми весь день: «События входа» (успешные и неудачные входы) и «Безопасностные аудиты» (сброс пароля, смена ролей, обновление API‑ключей). Когда клиент сообщает о подозрительной активности, команда фильтрует по пользователю, смотрит последние часы и экспортирует короткий отчёт.

До партиционирования всё лежало в одной большой таблице events. Она быстро росла, и даже простые запросы начали тянуться, потому что база просматривала много старых строк. Хранение было болезненно: ночная задача удаляла старые строки, но большие DELETE занимали много времени, создавали блоут и мешали обычному трафику.

После партиционирования по месяцам (по времени события) рабочий процесс улучшился. Админ‑панель требует временной фильтр, поэтому большинство запросов коснулись одной‑двух партиций. Страницы загружаются быстрее, потому что PostgreSQL игнорирует партиции вне диапазона. Хранение стало рутинным: вместо удаления миллионов строк вы просто удаляете старые партиции.

Одна вещь остаётся сложной: полнотекстовый поиск по «всей истории». Если кто‑то ищет IP или расплывчатую фразу без ограничения по дате, партиционирование не делает это дешёвым. Решение обычно в продукте: по умолчанию ограничивать поиск по времени и делать «последние 24 часа / 7 дней / 30 дней» очевидным путём.

Практические следующие шаги, которые работают чаще всего:

  • Сначала спроектируйте фильтры админ‑панели. Запишите, какие поля используют и какие должны быть обязательными.
  • Выберите партиции, соответствующие тому, как вы просматриваете данные. Месячные партиции — хороший старт; переходите на недельные только когда объём заставит это сделать.
  • Сделайте временной диапазон первоклассным фильтром. Если UI позволяет «нет даты», ожидайте медленную страницу.
  • Согласуйте индексы с реальными фильтрами. Когда время всегда присутствует, стратегия индекса «время‑первым» часто является правильной отправной точкой.
  • Установите правила хранения, совпадающие с границами партиций (например, хранить 13 месяцев и удалять всё старше).

Если вы строите внутреннюю админ‑панель с AppMaster (appmaster.io), стоит заложить эти допущения рано: рассматривайте временные фильтры как часть модели данных, а не только как выбор UI. Это небольшое решение защищает производительность запросов по мере роста объёма логов.

Вопросы и ответы

Когда партиционирование PostgreSQL действительно оправдано для таблиц событий или аудита?

Партиционирование приносит максимальную пользу, когда ваши обычные запросы ограничены по времени (например, «последние 24 часа» или «последние 7 дней») и таблица стала настолько большой, что индексы и обслуживание начинают создавать проблемы. Если же основной сценарий — «вся история для пользователя X», партиционирование может добавить накладные расходы, если вы не заставите UI использовать временные фильтры и не добавите правильные индексы на партиции.

Какой метод партиционирования лучше всего подходит для логов и аудита?

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

Как выбрать правильный ключ партиционирования для таблицы аудита?

Выбирайте поле, по которому пользователи сначала и почти всегда фильтруют. В большинстве админ‑панелей это временной диапазон, поэтому партиционирование по времени — самый предсказуемый выбор. Помните, что это долгосрочное решение: изменение ключа партиционирования позже — серьёзная миграция.

Почему партиционирование по user_id обычно плохая идея?

Используйте ключи, создающие управляемое число партиций. Избегайте высококардинальных полей вроде user_id, session_id или request_id, они могут порождать тысячи партиций и усложнить планирование и обслуживание без стабильного выигрыша в скорости.

Партиционировать по created_at или occurred_at?

Партиционируйте по created_at, если вам важна операционная стабильность и вы не можете доверять позднему поступлению событий (очереди, повторные попытки, офлайн‑клиенты). Партиционируйте по occurred_at, если главный кейс — «что произошло в этом окне» и время события надёжно. Часто компромисс — партиционировать по created_at, а для фильтрации индексировать occurred_at.

Должен ли UI админ‑панели требовать временной диапазон?

Да. После введения партиционирования временной диапазон должен быть обязательным фильтром в админ‑интерфейсе. Без него PostgreSQL может просмотреть много или все партиции, и страницы будут медленными. Хороший дефолт — «последние 24 часа», а «вся история» — явный, осознанный выбор.

Что может случайно сломать отбрасывание партиций в запросах?

Часто — да. Обёртки над ключом партиционирования (например, приведение к date) или фильтрация по другому временно́му столбцу могут помешать pruning. Держите условие в простом виде, например created_at BETWEEN X AND Y, чтобы PostgreSQL мог отбрасывать партиции.

Какой подход к пагинации лучше для партиционированных таблиц событий?

Избегайте глубокого OFFSET‑пагинации, она заставляет базу пропускать много строк. Лучше курсорная пагинация: «загрузить события раньше этого (timestamp, id)», она использует индексы и остаётся производительной по мере роста таблицы.

Как партиционирование влияет на уникальные ограничения и идентификаторы?

В PostgreSQL некоторые уникальные ограничения на партиционированных таблицах должны включать ключ партиционирования, иначе их нельзя гарантировать глобально. Практичный паттерн — составная уникальность вроде (created_at, id) при условии, что created_at — ключ партиции. Если нужен глобально уникальный идентификатор, используйте UUID и обработку уникальности внимательнее.

Какая самая простая стратегия хранения после партиционирования?

Самое простое — удалять старые партиции. Это быстро и избегает раздувания и дополнительной работы VACUUM, связанной с большими DELETE. Важно согласовать правила хранения с границами партиций и автоматизировать создание будущих партиций и удаление устаревших.

Легко начать
Создай что-то невероятное

Экспериментируйте с AppMaster с бесплатной подпиской.
Как только вы будете готовы, вы сможете выбрать подходящий платный план.

Попробовать AppMaster
Партиционирование PostgreSQL для таблиц событий в аудит‑логах | AppMaster