Аналитика: 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 на тех же вымышленных темах.