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

Как правильно настроить секционирование таблиц в PostgreSQL, чтобы избежать ошибки "ограничение уникальности в секционированной таблице должно включать все секционирующие столбцы"? Например, при создании таблицы "users" и указании секционирования по столбцу "created_at". Какой из вариантов будет более предпочтителен: создание составного PRIMARY KEY или использование обычного индекса по столбцу id с точки зрения эффективности?
  • 19 января 2024 г. 9:48
Ответы на вопрос 3
Выбор метода секционирования таблиц зависит от вашего приложения, доступного оборудования и ожидаемого вида запросов. В PostgreSQL существует несколько типов секционирования:

1. Диапазонное (Range Partitioning): Подходит для данных, которые естественно упорядочены и нуждаются в частом перебалансировании, например, временные ряды.
2. Списковое (List Partitioning): Подходит, когда ваши ключи могут быть сгруппированы в набор предопределённых значений, например, для стран или статусов.
3. Хэш-секционирование (Hash Partitioning): Подходит для равномерного распределения данных по секциям, когда нет логического диапазонного ключа.

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

Предположим, у вас есть таблица `users` секционированная по дате создания `created_at`. В простом случае, создание обычного индекса по столбцу `id` не сработает, потому что `id` не содержит секционирующего столбца `created_at`. Одним из решений является создание составного первичного ключа, который включает в себя `created_at`.

Пример создания такой секционированной таблицы:

```sql
CREATE TABLE users (
    id SERIAL,
    created_at TIMESTAMPTZ NOT NULL,
    username TEXT NOT NULL,
    PRIMARY KEY (created_at, id)
) PARTITION BY RANGE (created_at);
```

Здесь у вас есть составной первичный ключ, который состоит из `created_at` и `id`. Выбор и использование составного ключа может быть полезным:

- Улучшение производительности запросов, которые фильтруются и сортируются по колонкам, включённым в ключ.
- Поддерживание уникальности `id` в пределах каждой секции, определяемой `created_at`.

Однако также стоит учитывать потенциальные недостатки:

- Увеличение размера индекса из-за добавления дополнительных данных.
- Более сложные запросы на поиск по `id`, так как теперь потребуется указывать `created_at`.

Возможно, вам будет достаточно уникальных индексов по столбцам, не включающим `created_at`, если логика вашего приложения гарантирует, что такие конфликты не произойдут. Например, если вы знаете, что `id` является глобально уникальным и создаётся вне таблицы `users`, то можете использовать обычный индекс на `id`. 

Но если вам все же нужно гарантировать уникальность на уровне базы данных и вам необходимо использовать первичный ключ, тогда составной ключ — это путь, который необходимо выбрать для секционированной таблицы в PostgreSQL. Помните, что любое уникальное о
Можно объявить PK индивидуально на каждой партиции. Глобально-уникального индекса всё равно нет. 
Составной PK включающий ключ партицирования логичным образом изменит своё поведение.

PS: в чём вы предполагаете смысл от BY HASH ("created_at")?
PPS: под пользователями понимаются не люди? Просто людей на Земле маловато чтобы имело смысл делать партицирование по пользователям.
Тут 2 решения: 
- Ключ партиционирования - "id"
- Использовать партиционирование по диапазону - BY RANGE ("created_at") .
Похожие вопросы