OLTP (online transaction processing) — много коротких операций над отдельными записями: оформить заказ, обновить профиль. Нужно быстро достать или изменить всю строку по ключу. OLAP (analytics) — мало тяжёлых запросов по огромным объёмам: выручка по дням и регионам за год. Нужно прочитать несколько колонок у миллиардов строк.
Строковое хранение (PostgreSQL, MySQL): все поля строки лежат рядом на странице. Чтение строки по ключу — одна страница. Но запрос SUM(amount) GROUP BY day прочитает все страницы целиком, включая десятки ненужных колонок.
Колоночное хранение (ClickHouse, Vertica, BigQuery, Parquet): значения каждой колонки хранятся отдельно и подряд. Выигрыш:
- читаем только нужные колонки — запрос по 3 колонкам из 100 читает в ~30 раз меньше;
- сжатие — значения одного типа и часто повторяются (статус, страна, дата): кодирование словарём, RLE, дельта-кодирование для времени дают сжатие в 5–20 раз, а значит, ещё меньше чтения с диска;
- векторное выполнение — обработка блоками по тысячам значений с SIMD-инструкциями, мало ветвлений, хороший кэш;
- разреженные индексы и сортировка по ключу позволяют пропускать целые блоки по min/max.
Цена: вставить одну строку — значит дописать в каждую колонку; изменить или удалить — дорого. Поэтому данные пишут пачками (тысячи строк за раз), а изменения реализуют асинхронными мутациями или схемами вроде ReplacingMergeTree. Точечный запрос «одна строка по id» тоже хуже, чем в строковой базе.
Как сочетают на практике: транзакции — в PostgreSQL, оттуда поток изменений (CDC, Kafka) — в ClickHouse для отчётов и дашбордов. Для озера данных — файлы Parquet в объектном хранилище. Есть и гибриды: колоночные расширения для PostgreSQL, HTAP-системы.