OLAP и OLTP: в чём разница простыми словами
OLTP — системы, которые обслуживают работу продукта мелкими транзакциями, OLAP — системы для тяжёлых аналитических запросов. Чем они отличаются по запросам, схеме и хранению, почему отчёты не строят на рабочей базе и что такое OLAP-куб.
Содержание статьи
Вам нужен отчёт: выручка по каналам привлечения за каждый месяц квартала. Вы пишете запрос, отправляете его в рабочую базу приложения, а через десять минут в чат приходит разработчик: «Кто сейчас грузит прод? У пользователей тормозит оплата». Запрос правильный, база тоже правильная — просто она создана для другой работы. Разница между OLTP и OLAP как раз про это: одни системы обслуживают продукт, другие отвечают на вопросы о нём.
Коротко
- OLTP (online transaction processing) — обработка транзакций: много коротких операций чтения и записи, каждая касается одной или нескольких строк.
- OLAP (online analytical processing) — аналитическая обработка: мало запросов, но каждый просматривает и агрегирует большие объёмы данных.
- OLTP-базы обычно хранят данные строками и держат нормализованную схему с ограничениями. OLAP-системы чаще хранят данные столбцами и работают с денормализованными витринами.
- Тяжёлые отчёты не запускают на рабочей базе приложения: их переносят на реплику или в хранилище данных.
- DuckDB, на котором работает песочница SQL-курса, — это OLAP-движок, но базовый SQL в нём тот же, что и в PostgreSQL.
Что такое OLTP простыми словами
OLTP — это режим работы базы, в котором она обслуживает продукт в реальном времени. Пользователь зарегистрировался — в таблицу пользователей добавилась строка. Оплатил подписку — появилась строка в платежах, у подписки поменялся статус. Открыл профиль — база нашла одну запись по ключу и вернула её за миллисекунды.
Каждая такая операция маленькая, но их много, и они идут одновременно от тысяч людей. Поэтому главное для OLTP-системы — быстро и без ошибок выполнять мелкие изменения. Если оплата прошла, запись о ней должна сохраниться целиком. Если сбой случился посередине, не должно остаться половины операции: деньги списаны, а подписка не продлена.
Для этого OLTP-базы используют транзакции. Несколько изменений объединяются в одно целое: либо применяются все, либо ни одно. Ниже пример записи оплаты в терминах учебной базы. В песочнице он не выполнится, она принимает только SELECT и WITH, но так выглядит типичная работа рабочей базы приложения.
begin;
insert into payments (payment_id, user_id, paid_at, amount, plan, payment_type)
values (1252, 45, date '2026-09-20', 19.00, 'basic', 'renewal');
update subscriptions
set status = 'active'
where user_id = 45;
commit;Что такое OLAP простыми словами
OLAP — это режим, в котором базу спрашивают не про одного пользователя, а про всех сразу. Сколько выручки принёс каждый канал за месяц. Как менялось удержание когорт. Какая доля оплат приходится на тариф team. Такой запрос читает тысячи и миллионы строк, группирует их и возвращает небольшую таблицу итогов.
Аналитических запросов в разы меньше, чем операций в продукте, и от них не ждут ответа за миллисекунды: секунды, а иногда и минуты допустимы. Зато они тяжёлые, и система под них устроена иначе. Данные в неё обычно загружают пачками — раз в час или раз в сутки, — а не пишут построчно.
Сам термин OLAP появился в начале 1990-х как противопоставление OLTP: одни системы записывают события бизнеса, другие помогают их анализировать. Сегодня под OLAP чаще всего имеют в виду аналитические базы и хранилища данных.
Чем OLAP отличается от OLTP: сравнение в таблице
Граница не абсолютная. На небольших объёмах аналитику спокойно считают и в PostgreSQL: учебная база курса умещается в любой СУБД. Различия проявляются, когда данных становится много и одна система начинает мешать другой.
| OLTP | OLAP | |
|---|---|---|
| Кто отправляет запросы | приложение, тысячи пользователей одновременно | аналитики, BI-отчёты, расчёты по расписанию |
| Типичный запрос | найти, вставить или изменить одну запись по ключу | сгруппировать и агрегировать большую таблицу |
| Строк на один запрос | единицы | от тысяч до миллиардов |
| Как появляются данные | постоянные мелкие вставки и обновления | загрузка пачками, обновления редки |
| Ожидаемая задержка | миллисекунды | секунды, иногда минуты |
| Схема | нормализованная: ключи, ограничения, без дублей | денормализованные витрины, схема «звезда» |
| Хранение | обычно строками | обычно столбцами |
| Примеры систем | PostgreSQL, MySQL | ClickHouse, BigQuery, DuckDB |
Почему аналитические базы хранят данные столбцами
Представьте таблицу payments на бумаге. Строковое хранение кладёт на диск каждую оплату целиком: номер, пользователь, дата, сумма, тариф, тип — потом следующая оплата. Чтобы найти одну оплату, достаточно прочитать одно место на диске. Для OLTP это идеально.
Теперь нужно сложить суммы по месяцам. Из шести колонок payments запросу нужны две: paid_at и amount. При хранении строками система всё равно прочитает остальные четыре, потому что они лежат вперемешку с нужными. При хранении столбцами все даты лежат подряд, все суммы — подряд, и остальные колонки можно не трогать.
Второй выигрыш — сжатие. В колонке channel таблицы users всего четыре разных значения на 4613 строк. Однотипные и повторяющиеся значения, лежащие рядом, сжимаются намного лучше, чем строки из разнородных полей. Меньше байт на диске — меньше чтения. Платить за это приходится записью: вставить одну строку в колоночное хранилище дороже, потому что она разложена по разным местам.
В колоночных базах select * по большой таблице дорогой: он поднимает все колонки. Перечисляйте только нужные поля — в облачных хранилищах с оплатой за прочитанные данные это ещё и дешевле.
Один и тот же вопрос как OLTP-запрос и как OLAP-запрос
Возьмём учебную базу курса. Первый вопрос — из мира OLTP: какая последняя оплата у пользователя 45? Так спрашивает личный кабинет, когда показывает дату следующего списания. Запрос ищет по одному ключу и возвращает одну строку.
select payment_id, paid_at, amount, plan, payment_type
from payments
where user_id = 45
order by paid_at desc
limit 1;Как выглядит аналитический запрос на той же базе
Ответ — оплата 998 от 21 августа: 19 долларов за тариф basic, продление. В рабочей базе такой запрос опирается на индекс по user_id и не зависит от того, сколько в таблице других пользователей.
Второй вопрос — из мира OLAP: сколько выручки принёс каждый канал в каждом месяце? Здесь нужны все 1251 оплата, соединение с таблицей пользователей ради канала и группировка по двум признакам.
Учебная база SQL-курса, DuckDB. Сумма оплат по месяцу оплаты. Канал paid_search приводит регистрации с 1 июля, поэтому в июне у него нет оплат.
select
u.channel,
date_trunc('month', p.paid_at)::date as month,
count(*) as payments,
sum(p.amount) as revenue
from payments as p
join users as u on u.user_id = p.user_id
group by u.channel, month
order by u.channel, month;Что показывает сравнение двух запросов
Итог по месяцам — 3983, 10 868 и 15 788 долларов, всего 30 639. Из шести колонок payments запросу понадобились три (user_id, paid_at, amount), из пяти колонок users — две. Это типичная форма аналитического запроса: читает много строк, но мало колонок, и возвращает несколько строк итогов.
На учебной базе оба запроса выполняются мгновенно, потому что данных мало. Разница становится ощутимой на миллионах оплат: первый запрос по-прежнему читает одну строку через индекс, а второй должен пройти по всей таблице. В строковой базе он поднимет все колонки, в колоночной — только три нужные.
Песочница курса работает на DuckDB. Это встраиваемая колоночная OLAP-база: она запускается внутри процесса, без отдельного сервера, и рассчитана на аналитические запросы. Поэтому запросы из курса — группировки, оконные функции, когорты — в ней естественны. Синтаксис базовых конструкций при этом почти совпадает с PostgreSQL, и навыки переносятся между системами.
Почему нельзя строить отчёты на рабочей базе
Рабочая OLTP-база настроена так, чтобы тысячи мелких операций шли без очереди. Тяжёлый аналитический запрос ломает этот расчёт: он долго занимает процессор, читает с диска гигабайты данных и вытесняет из памяти кэш, на который рассчитывали быстрые запросы приложения. Пользователи видят это как медленную оплату или зависшую страницу.
В PostgreSQL у долгого запроса есть и менее заметное последствие: пока открыта старая транзакция, база не может очистить устаревшие версии строк, и таблицы разрастаются. Разработчики обычно замечают это позже, чем тормоза.
Поэтому аналитику выносят с рабочей базы. Самый простой вариант — реплика только для чтения: копия базы, куда запросы аналитика уходят вместо основной. Но реплика остаётся OLTP-базой со строковым хранением и нормализованной схемой, а длинный запрос на ней может прерваться из-за конфликта с потоком изменений от основной базы. Следующий шаг — хранилище данных (DWH), куда данные регулярно перегружаются и где под аналитику строят витрины.
- Разовый небольшой запрос с фильтром по индексу — обычно допустим, если с командой разработки есть договорённость.
- Регулярные отчёты и дашборды — на реплике или в хранилище, не на основной базе.
- Запросы, которые проходят по всей большой таблице, — в хранилище или в аналитической базе.
Как данные попадают из OLTP в OLAP
Между двумя мирами стоит процесс загрузки. Его называют ETL или ELT: данные извлекают из рабочих баз, преобразуют и загружают в хранилище. Порядок букв показывает, где происходит преобразование — до загрузки или уже внутри хранилища.
По дороге меняется форма данных. В OLTP-схеме таблицы нормализованы: канал хранится у пользователя, тариф — у подписки, сумма — у оплаты, и чтобы собрать отчёт, нужно несколько соединений. В хранилище из них собирают витрину, где у каждой оплаты уже стоят канал, страна и месяц. Дублирование данных, которого OLTP избегает, здесь делается нарочно: оно избавляет каждый отчёт от одних и тех же соединений.
У такой схемы есть цена: данные в хранилище отстают от продукта на время между загрузками. Для месячного отчёта задержка в сутки не важна, для мониторинга платёжного сбоя — критична. Это стоит проверять до того, как строить на хранилище оперативные алерты.
Что такое OLAP-куб
Раньше слово OLAP почти всегда означало куб. OLAP-куб — это заранее посчитанные агрегаты по нескольким измерениям: например, выручка по каналу, месяцу и стране. Пользователь в интерфейсе «вращает» куб, проваливается с года до месяца, фильтрует по стране, а система отдаёт готовые суммы, не пересчитывая их из сырых строк.
Кубы появились, когда пройти по всей таблице было слишком долго. Сейчас колоночные базы считают агрегаты по сырым данным достаточно быстро для многих задач, и кубы в чистом виде встречаются реже. Сама идея осталась: измерения, меры, срезы и детализация — это язык любой BI-системы, а предрасчитанные агрегаты по-прежнему используют там, где отчёт открывают сотни людей.
HTAP: можно ли совместить транзакции и аналитику
HTAP (hybrid transactional/analytical processing) — подход, при котором одна система обслуживает и транзакции, и аналитические запросы. Обычно внутри неё всё равно два представления данных: строковое для записи и колоночное для чтения, которые система синхронизирует сама.
Для аналитика из этого следует одно: даже если база называет себя гибридной, вопрос о нагрузке на рабочие операции никуда не девается. Как именно система разделяет эти нагрузки, стоит выяснить в её документации и у команды, которая её поддерживает, а не предполагать по названию.
Что читать дальше
Здесь OLAP и OLTP разобраны как понятия. Дальше — о том, как устроен путь данных до отчёта и как писать аналитические запросы.
Материалы по теме

ETL: что это простыми словами, этапы и чем ETL отличается от ELT
ETL — процесс, который забирает данные из источников, приводит их в порядок и загружает в хранилище. Этапы extract, transform, load на примере продукта, разница ETL и ELT, инкрементальная загрузка, идемпотентность и SQL-проверки качества данных.

DWH, витрина данных и data lake: что это и чем они отличаются
DWH — хранилище данных для анализа, витрина — готовая таблица под конкретную задачу, data lake — хранилище сырых файлов. Чем DWH отличается от базы приложения, из каких слоёв состоит, как выглядит витрина на SQL и почему в двух витринах бывают разные цифры.

LATERAL JOIN в SQL: последняя запись, top-N на пользователя и функции в FROM
LATERAL JOIN на реальной учебной базе: последний платёж пользователя со всеми полями, разница между LEFT и CROSS, почему подзапрос с агрегатом никогда не отбрасывает строки, три последних события на человека, индекс, без которого LATERAL читает таблицу на каждой строке, и когда хватит GROUP BY, DISTINCT ON или окна.