Учебник веб-разработки
Разделы учебника
На этой странице

VIII. Системы хранения

Аналитика: OLTP, OLAP и столбцовое хранение

Оглавление · Модели хранения · PostgreSQL

Задача: отличить изменение операционных данных от анализа большого набора. Нужны отношения, предикаты и агрегации.

Разные формы работы

НагрузкаУчебный вопросЧто важно
OLTPСохранить правку одной статьиИнварианты, короткие транзакции, конкуренция
OLAPПосчитать просмотры по темам за месяцОбъём чтения, агрегация, свежесть итогов

Это профиль нагрузки, не жёсткое разделение продуктов. PostgreSQL может выполнять аналитику; отдельная система нужна по измеренной задаче. В Atmanki аналитическая БД и сбор пользовательских просмотров пока не реализованы.

Строки и колонки

Для данных (id, topic, duration) представим две организации:

По строкам:  (1, react, 10), (2, react, 20), (3, data, 100)
По колонкам: id       = [1, 2, 3]
             topic    = [react, react, data]
             duration = [10, 20, 100]

При чтении целой записи полезна близость её полей. При суммировании duration по topic полезно читать только нужные колонки и обрабатывать их пакетами; однотипные значения также дают возможности сжатия. Реальный формат сложнее этих массивов: есть блоки, кодеки, индексы и метаданные. ClickHouse — пример столбцовой SQL-системы для OLAP. Введение ClickHouse.

Столбцовое хранение не гарантирует превосходство на любой нагрузке. Изменение одной записи, JOIN и ограничения конкретного движка требуют отдельного изучения. Wide-column из главы о моделях — другое семейство: совпадение слова «колонка» не делает Cassandra аналогом аналитической организации ClickHouse.

GROUP BY и единица наблюдения

Иллюстративный запрос PostgreSQL 17 с вымышленными данными:

WITH lesson_event(id, topic, duration) AS (
  VALUES (1, 'react', 10), (2, 'react', 20),
         (3, 'data', 100), (4, 'react', 30)
)
SELECT topic, count(*) AS events, sum(duration) AS total,
       avg(duration) AS mean
FROM lesson_event
GROUP BY topic
ORDER BY topic;

Ожидаются data: count=1, total=100, mean=100 и react: count=3, total=60, mean=20. GROUP BY объединяет строки по ключу, агрегаты считают группу. Группировка PostgreSQL. Этот SQL в текущем этапе не исполнялся.

Задайте единицу: событие, пользователь, сессия или публикация. Повторная доставка события увеличит count(*) без дедупликации; JOIN с метками может размножить строки. COUNT(DISTINCT id) отвечает на другой вопрос и требует корректного значения id. Фильтр времени и политика NULL также меняют результат.

Аналитическая копия

Исходник схемы
flowchart LR
  Source["Операционные данные"] --> Transfer["Пакетный перенос / журнал изменений"]
  Transfer --> Copy["Аналитическая копия"]
  Copy --> Aggregate["Агрегации и отчёт"]
  Transfer --> Check["Контроль полноты и задержки"]

Это будущая архитектура, не текущий сервис Atmanki. Копия может отставать; отчёт должен указывать период, момент обновления и полноту. Нужно обработать удаления, исправления и повтор переноса, а не только первое добавление строки.

Предагрегат экономит чтение, но теряет часть подробностей. Сохранённое среднее без count нельзя корректно объединить с другим средним. Для среднего храните как минимум сумму и количество; для других показателей нужны другие достаточные итоги.

Конечный набор и поток

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

Для учебного счётчика задайте интервал [start, end), часовую зону отображения и политику поздних данных. Исправление результата — отдельный переход, а не ошибка арифметики. Подробная потоковая лаборатория остаётся в программе.

Практика

Посчитайте один набор напрямую и частями. Проверьте сумму, count и среднее. Добавьте дубликат события, размножающий JOIN и позднюю запись: укажите, где меняется смысл метрики. Для отчёта составьте контракт свежести и полноты.

Не копируйте production-данные в публичный учебник. Следующая глава даёт локальную модель MapReduce на тех же вымышленных темах.