JSONB, партиционирование и расширения SQL в PostgreSQL
Раздел 8.11, шаг 4 из 12. Дальше — PL/pgSQL и триггеры.
JSONB как «NoSQL внутри Postgres»
PostgreSQL хранит JSON в двух формах:
| Тип | Хранение | Когда |
|---|---|---|
| json | Текст с сохранением пробелов/порядка ключей | Точная сериализация |
| jsonb | Бинарное, нормализованное | Фильтры, индексы, операторы |
Типовой паттерн — гибридная схема: жёсткие столбцы для ключей и FK, JSONB для редко фильтруемых или эволюционирующих атрибутов.
CREATE TABLE products (
id bigserial PRIMARY KEY,
sku text NOT NULL UNIQUE,
price numeric(12,2) NOT NULL,
attributes jsonb NOT NULL DEFAULT '{}'
);
Операторы извлечения и фильтрации
| Оператор | Действие |
|---|---|
-> | JSON-объект по ключу (json) |
->> | Значение как text |
#> | Путь '{a,b,c}' |
@> | Левый JSON содержит правый |
? / `? | /?&` |
|| | Слияние объектов |
SELECT sku, attributes ->> 'color' AS color
FROM products
WHERE attributes @> '{"brand": "acme"}'
AND attributes ? 'warranty_months';
Обновление документов
UPDATE products
SET attributes = jsonb_set(attributes, '{stock}', '42', true)
WHERE sku = 'WIDGET-1';
UPDATE products
SET attributes = attributes - 'deprecated_field'
WHERE id = 100;
Индексы
CREATE INDEX idx_products_attrs ON products USING gin (attributes jsonb_path_ops);
CREATE INDEX idx_products_color ON products ((attributes ->> 'color'));
Полный практикум с JOIN, агрегатами и EXPLAIN — 3.07/66.
Оконные функции и CTE
Подробная теория и примеры уже в энциклопедии:
- Оконные функции —
ROW_NUMBER,LAG,PARTITION BY. - CTE и рекурсия —
WITH,MATERIALIZED, модифицирующие CTE.
В production PostgreSQL 12+ планировщик может inline CTE (не материализовать), если это выгодно. Принудительная материализация:
WITH big AS MATERIALIZED (
SELECT … FROM huge_table WHERE …
)
SELECT … FROM big JOIN …;
Комбинация JSONB + оконные функции — типовой аналитический запрос:
SELECT id,
payload ->> 'region' AS region,
(payload ->> 'amount')::numeric AS amount,
SUM((payload ->> 'amount')::numeric) OVER (
PARTITION BY payload ->> 'region'
ORDER BY created_at
) AS running_total
FROM events
WHERE created_at >= now() - interval '7 days';
Declarative partitioning
Партиционирование делит одну логическую таблицу на физические части (partition). Планировщик pruning отсекает лишние партиции по условию WHERE.
RANGE — по диапазону (даты, ID)
CREATE TABLE measurements (
id bigserial,
device_id int NOT NULL,
measured_at timestamptz NOT NULL,
value double precision
) PARTITION BY RANGE (measured_at);
CREATE TABLE measurements_2025_01 PARTITION OF measurements
FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');
CREATE TABLE measurements_2025_02 PARTITION OF measurements
FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');
LIST — по списку значений
CREATE TABLE orders (
id bigint,
region text,
amount numeric
) PARTITION BY LIST (region);
CREATE TABLE orders_eu PARTITION OF orders
FOR VALUES IN ('DE', 'FR', 'IT');
HASH — равномерное распределение
CREATE TABLE sessions (
id uuid PRIMARY KEY,
user_id bigint,
data jsonb
) PARTITION BY HASH (user_id);
CREATE TABLE sessions_p0 PARTITION OF sessions
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
-- … p1, p2, p3
Управление жизненным циклом данных
| Задача | Подход с партициями |
|---|---|
| Удаление старых логов | DROP TABLE measurements_2024_01 — мгновенно, без VACUUM всей таблицы |
| Архив | DETACH PARTITION → перенос на cold storage |
| Загрузка bulk | COPY в новую партицию, затем ATTACH PARTITION |
| Разные индексы | Разные индексы на «горячей» и «холодной» партиции |
Автоматическое создание партиций — расширение pg_partman или cron + DDL.
Ограничения и первичные ключи
В partitioned table PK/UNIQUE должны включать ключ партиционирования (или использовать глобальный индекс в будущих версиях — следите за release notes).
-- PK только на id без ключа партиции — ошибка в PG до обходных схем
PRIMARY KEY (id, measured_at)
Когда JSONB, когда отдельная таблица
| Критерий | JSONB | Нормализация |
|---|---|---|
| Схема стабильна, много JOIN | — | отдельные таблицы |
| Редкие атрибуты, интеграции | JSONB | — |
| Жёсткая валидация | CHECK + jsonb | столбцы + constraints |
| Поиск по вложенным полям | GIN + @> | вынести в столбец |
Практика
- Перенесите «широкую» таблицу логов на RANGE по месяцу, сравните время
DELETEстарых данных vsDROP PARTITION. - Добавьте GIN на JSONB и снимите
EXPLAINдля@>(шаг 2). - Напишите отчёт с оконной функцией по JSONB-полю amount.
Связанные материалы
- Индексы GIN и BRIN
- PL/pgSQL — триггеры на изменение JSONB
- NoSQL — о разделе — когда Postgres недостаточен
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). MVCC, XID, снимки данных, системные поля xmin/xmax, VACUUM и autovacuum, bloat, wraparound, процессы postmaster, Shared Buffers и WAL. pg_dump, pg_basebackup, PITR, pg_probackup, Wal-G, стратегия 3-2-1, восстановление в Kubernetes и после failover. pg_stat_statements, pg_stat_activity, auto_explain, pgBadger, Prometheus postgres_exporter, типовые метрики SLA и алерты. Ansible role для установки Postgres, шаблоны postgresql.conf, Terraform для RDS и managed PostgreSQL, GitOps паттерны для инфраструктуры БД. EXPLAIN и EXPLAIN ANALYZE, B-tree, GiST, SP-GiST, GIN, BRIN, частичные и составные индексы, типовые ошибки планировщика. Тонкая настройка памяти (shared_buffers, work_mem, maintenance_work_mem), I/O (effective_cache_size, random_page_cost), WAL, checkpoint и autovacuum. Хранимые функции и процедуры PL/pgSQL, row-level и statement triggers, event triggers, асинхронные события через NOTIFY и LISTEN без polling. Streaming replication, logical replication, read replicas и Hot Standby, failover, connection pooling через PgBouncer — transaction и session pooling. Официальный образ postgres, volumes для PGDATA, переменные окружения, docker-compose с healthcheck, типовые ошибки контейнеризации СУБД. Managed PostgreSQL (RDS, Cloud SQL, Yandex Managed), StatefulSet, PersistentVolume, секреты, операторы Crunchy/Zalando, anti-patterns stateful в K8s. Patroni и DCS, сравнение с Greenplum и CockroachDB, когда нужен sharding, Citus, выбор архитектуры под OLTP и аналитику. Краткое резюме раздела 8.11 — архитектура, оптимизация, эксплуатация в контейнерах и Kubernetes, HA, бэкапы и автоматизация.Архитектура PostgreSQL и внутреннее устройство
Бэкапы PostgreSQL и восстановление
Профилирование и мониторинг PostgreSQL
Автоматизация PostgreSQL — Ansible и Terraform
Продвинутая оптимизация PostgreSQL и индексы
Конфигурация PostgreSQL — postgresql.conf
PL/pgSQL, триггеры и NOTIFY/LISTEN в PostgreSQL
Репликация PostgreSQL, Hot Standby и PgBouncer
PostgreSQL в Docker
PostgreSQL в облаке и Kubernetes
HA-кластеры PostgreSQL и распределённые СУБД
Практикум PostgreSQL — итоги