Databases

Тома и представления

Том — именованная область хранения данных (диск, раздел, volume в Docker), представление (вьюха) — сохранённый SQL-запрос, который выглядит как таблица.

Что такое тома и представления

Это два независимых термина, которые объединяет только одно — оба дают имя чему-то, устроенному не так, как выглядит. Том (volume) — именованная область хранения, к которой обращаются как к диску. Представление (view, «вьюха») — сохранённый SQL-запрос, к которому обращаются как к таблице. Ничего общего между ними нет, и ниже они разобраны по отдельности.

Что такое том

Том (volume) — именованная область хранения данных, которая для системы выглядит как отдельный диск. В зависимости от контекста слово означает разные вещи:

Контекст Что такое том
Диски и разделы Логический раздел: C: в Windows, /dev/sda1 в Linux
LVM Логический том поверх группы физических дисков
СХД LUN — кусок ёмкости массива, отданный серверу
Docker Область данных, живущая отдельно от контейнера
Kubernetes Volume и PersistentVolume, подключаемые к подам

Общий смысл везде один: том отвязывает данные от конкретного носителя. Физически он может лежать на одном диске, на RAID-массиве из десяти дисков или на сетевом хранилище — потребитель видит просто устройство.

Тома в Docker

Самый частый контекст, в котором разработчик встречает слово. Контейнер эфемерен: удалили — данные внутри исчезли. Том решает эту проблему.

docker volume create pgdata

docker run -d --name db \
  -v pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:16

docker rm -f db          # контейнер удалён
docker run -d --name db2 -v pgdata:/var/lib/postgresql/data postgres:16
# данные на месте — том пережил контейнер
docker volume ls
docker volume inspect pgdata     # где физически лежит
docker volume prune              # удалить тома, которые никем не используются

Named volume против bind mount: -v pgdata:/data — том под управлением Docker, -v /home/user/data:/data — просто папка хоста. Для баз данных выбирают именованный том; bind mount удобен в разработке, чтобы править код без пересборки образа.

Осторожно с docker volume prune и docker-compose down -v: обе команды удаляют тома, и вместе с ними базу данных.

LVM

pvcreate /dev/sdb /dev/sdc          # физические тома
vgcreate data_vg /dev/sdb /dev/sdc  # группа томов
lvcreate -L 500G -n db_lv data_vg   # логический том

mkfs.ext4 /dev/data_vg/db_lv
mount /dev/data_vg/db_lv /var/lib/postgresql

lvextend -L +200G -r /dev/data_vg/db_lv   # расширить на живой ФС

Ценность LVM в последней строке: том расширяется без остановки и переразметки, а место берётся из пула дисков. Плюс снапшоты — мгновенный снимок тома перед рискованным обновлением.

Что такое представление (вьюха)

Представление (view, «вьюха») — сохранённый в базе SQL-запрос, к которому можно обращаться как к таблице. Своих данных у него нет: при каждом обращении СУБД подставляет и выполняет запрос заново.

CREATE VIEW active_customers AS
SELECT u.id, u.email, count(o.id) AS orders, sum(o.total) AS revenue
FROM users u
JOIN orders o ON o.user_id = u.id
WHERE u.deleted_at IS NULL
GROUP BY u.id, u.email;

SELECT * FROM active_customers WHERE revenue > 100000;

Зачем нужны:

  • Спрятать сложность. Запрос с пятью JOIN пишется один раз, а не копируется по коду.
  • Разграничить доступ. Аналитику дают права на представление без зарплат и телефонов, а не на исходную таблицу — это применение RBAC на уровне данных.
  • Совместимость. Схема поменялась, а представление сохраняет старый интерфейс для legacy-кода.

Чего вьюха не делает — не ускоряет запрос. Это подстановка текста, а не кеш: SELECT * FROM active_customers каждый раз выполняет всю группировку заново. Распространённое заблуждение — рассчитывать, что вынос тяжёлого запроса во view его оптимизирует.

Материализованное представление

CREATE MATERIALIZED VIEW revenue_by_day AS
SELECT date_trunc('day', created_at) AS day, sum(total) AS revenue
FROM orders GROUP BY 1;

CREATE UNIQUE INDEX ON revenue_by_day (day);       -- нужен для CONCURRENTLY

REFRESH MATERIALIZED VIEW CONCURRENTLY revenue_by_day;   -- без блокировки чтения

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

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

View Materialized view
Хранит данные Нет Да
Актуальность Всегда свежие На момент REFRESH
Скорость чтения Как исходный запрос Как обычная таблица
Индексы Нельзя Можно

Обновляемые представления

Простое представление без агрегатов и JOIN в PostgreSQL можно менять напрямую — INSERT и UPDATE уйдут в исходную таблицу. Как только появляются GROUP BY, DISTINCT или несколько таблиц, автоматически это не работает: нужен триггер INSTEAD OF.

Связанные термины

Готовы запустить GPU-задачу?

Запустить GPU-сервер