Расскажу простую историю с очень конкретным финалом. Я делаю агрегатор госзакупок Казахстана 10b.kz — мы парсим официальный портал госзакупок РК, планы, договоры, акты и казначейские платежи. Данных стало реально много: сотни миллионов строк. Сырьё лежало в PostgreSQL, и аналитика начала упираться в пол: каждый серьёзный отчёт — это полный скан и тяжёлый GROUP BY, который тянется секундами и минутами. Я перевёл всё на ClickHouse — и та же самая аналитика по таблице в 31 млн лотов стала отвечать за 0,08–0,5 секунды. Ниже — сначала на пальцах, в чём фокус, а потом — моя живая продовая конфигурация с точными цифрами.
Коротко для тех, кто спешит
Одна недорогая VPS (16 vCPU, 30 ГБ RAM) держит 781 млн строк / 192 ГиБ данных о госзакупках РК — без всякого кластера и шардинга.
Аналитика по таблице в 31 млн лотов отвечает за 0,08–0,5 секунды. Пик сканирования — 378 млн строк/сек и 3,9 ГиБ/сек на одном сервере.
Секрет ClickHouse не в хитром алгоритме, а в одной простой идее: колоночное хранение — читаем с диска только нужные столбцы, а не строки целиком.
ClickHouse — это не замена PostgreSQL, а другой инструмент. PostgreSQL — для транзакций (OLTP). ClickHouse — для аналитики (OLAP): много чтения, агрегации, полные сканы.
1. Что это вообще такое, на пальцах
Представьте обычную базу вроде PostgreSQL как толстую тетрадь, где данные записаны по строкам: одна строка — один лот, и все его поля (номер, заказчик, сумма, дата, статус…) лежат рядом, одной записью. Удобно, когда нужно достать или поправить одну конкретную запись целиком. Но когда ты хочешь просто сумму по одной колонке за год, приходится пролистать каждую строку целиком — вместе со всеми ненужными полями.
ClickHouse хранит данные по колонкам: все суммы лотов лежат подряд в одном месте, все даты — в другом, все имена заказчиков — в третьем. Нужна сумма по одной колонке — ClickHouse читает только её, а не всю таблицу. Плюс есть бонус: значения одного типа, лежащие подряд, жмутся в разы лучше, чем перемешанные поля строки. Отсюда вся магия — меньше читаем с диска, значит, быстрее отвечаем. Это и называется колоночной базой данных (хороший разбор темы есть и у MotherDuck, и у Fivetran).
Конкретный пример из моей боевой таблицы лотов (31,4 млн строк, 5,9 ГиБ). Один и тот же GROUP BY: если запросу нужны только 2 числовые колонки, ClickHouse читает с диска 330 МиБ вместо 5,9 ГиБ — примерно в 18 раз меньше. Строчной базе в любом случае пришлось бы поднять строки целиком.
Сколько реально прочитано с диска
Один GROUP BY по таблице лотов (31,4 млн строк, логически 5,9 ГиБ). Меньше — лучше.
Первый запрос трогает 2 колонки из ~60 → 0,08 с. Второй тянет ещё и длинное строковое имя заказчика → 6,6 ГиБ и 0,46 с. Тот самый эффект «читаем только нужное».
Отсюда сразу две суперсилы. (1) Column pruning — читаем только те колонки, что нужны запросу. (2) Сжатие 4.8× — одинаковые по типу значения подряд ужимаются в разы: у меня 355 ГиБ логических данных занимают на диске 74 ГиБ. Меньше байт на диске = меньше I/O = быстрее ответ.
2. Вчера опенсорс, сегодня компания за $15 млрд
Мне нравится эта история, потому что она про силу простой идеи. В 2009 году инженер-математик Алексей Миловидов в Яндексе затеял эксперимент: можно ли строить аналитические отчёты в реальном времени прямо из сырых, неагрегированных данных, которые к тому же постоянно доливаются. Три года он доказывал гипотезу — и в 2012-м ClickHouse пошёл в прод как движок Яндекс.Метрики, второй по величине системы веб-аналитики в мире.
В июне 2016-го проект открыли под лицензией Apache 2. В сентябре 2021-го из него выросла отдельная компания ClickHouse Inc. в Сан-Франциско (основатели — Aaron Katz, Alexey Milovidov и Yury Izrailevsky; стартовые $50 млн дали Index Ventures и Benchmark, среди участников был и Яндекс). А в январе 2026-го ClickHouse привлёк $400 млн при оценке $15 млрд (раунд Series D во главе с Dragoneer) — вдвое больше, чем годом раньше ($6,35 млрд в мае 2025). Всего компания подняла более $1 млрд.
Мораль. «Секрет» ClickHouse — не хитрый алгоритм, а одна простая идея (колоночное хранение для аналитики), доведённая до совершенства и заточенная под скорость. Миловидов, кстати, до сих пор сооснователь и CTO — редкий случай, когда автор опенсорс-эксперимента остаётся техническим сердцем компании за $15 млрд.
3. Честно: это не замена PostgreSQL
Скажу прямо, потому что сам долго думал, что выбрать под свой агрегатор. Главное, что я понял: ClickHouse — это НЕ замена PostgreSQL, это другой инструмент под другую задачу. Это не «лучше/хуже», это «для разного».
PostgreSQL — OLTP
- Для транзакций: заказы, платежи, регистрации.
- Точечные вставки и апдейты, где важна консистентность каждой записи.
- Достать/поправить одну строку целиком — это его стихия.
- Строчное хранение — идеально для «одна операция = одна запись».
ClickHouse — OLAP
- Для аналитики: дашборды, отчёты, поиск по истории.
- Много чтения и агрегаций по сотням миллионов строк.
- Полные сканы без предрасчёта и без индекса под каждый запрос.
- Плохо подходит для частых точечных
UPDATE/DELETE.
Разницу OLTP vs OLAP проще всего запомнить так: OLTP — это «много мелких операций над отдельными записями» (банкомат), OLAP — «одна тяжёлая операция над всей историей» (годовой отчёт). ClickHouse не нужен, если данных мало, и он не про частые точечные апдейты.
Вывод простой и честный: если данных реально много и нагрузка аналитическая — дашборды, отчёты, поиск по истории — пробуй ClickHouse, не пожалеешь. Для транзакций оставь PostgreSQL.
4. Наша схема: 781 млн строк на одной VPS
Теперь как это выглядит у меня в бою. Мы парсим официальный API goszakup.gov.kz (плюс Самрук, казначейство, планы). Раньше сырьё было в PostgreSQL, и аналитика упиралась в полные сканы и тяжёлые GROUP BY. Сейчас всё в ClickHouse, организованном как многослойная (medallion) ELT-архитектура — сырьё очищается и превращается в витрины слой за слоем:
| Слой | База | Что там |
|---|---|---|
| raw | goszakup_raw | Сырые выгрузки API как есть, дедуп через ReplacingMergeTree |
| stg | goszakup_stg | Очистка, типизация, нормализация |
| dmrt | goszakup_dmrt | Витрины — широкие денормализованные таблицы |
| refs | goszakup_refs | 35 справочников (статусы, КАТО, ЕНС ТРУ, валюты) |
| ai | goszakup_ai | ML-обогащение лотов (категоризация, маржа) |
Ключевые таблицы — вот из чего складываются эти 781 млн строк и 192 ГиБ. Обратите внимание на движок: MergeTree для стабильных данных и ReplacingMergeTree там, где ETL постоянно доливает новые версии строк.
| Таблица | Строк | Размер | Движок |
|---|---|---|---|
| goszakup_raw.plans_all | 42,0 млн | 11,3 ГиБ | ReplacingMergeTree |
| goszakup_dmrt.lots | 31,4 млн | 5,9 ГиБ | MergeTree |
| goszakup_stg.trd_app | 52,5 млн | 4,4 ГиБ | MergeTree |
| goszakup_stg.contract_all | 14,4 млн | 4,5 ГиБ | ReplacingMergeTree |
| goszakup_stg.treasury_pay | 11,5 млн | 2,8 ГиБ | ReplacingMergeTree |
| goszakup_stg.acts | 32,7 млн | 2,0 ГиБ | MergeTree |
Как ClickHouse заменил UPSERT-ы из PostgreSQL. Сырой слой на ReplacingMergeTree — это замена INSERT ... ON CONFLICT: ETL просто пишет новые версии строк по ключу, а ClickHouse сам схлопывает дубли при фоновом слиянии. Никаких блокировок и гонок на апдейтах — загрузка идемпотентна.
5. Железо и конфигурация
Никакого кластера. Одна машина. Вот вся правда о железе:
ОС — Ubuntu 24.04 LTS, ClickHouse 25.12 под systemd, аптайм на момент замеров — 4 недели. Главный нюанс: сервер «горячий» — рядом на этой же машине молотит Python-ETL, который тоже хочет память. Поэтому я подрезал ClickHouse, чтобы он не съел всё под кэши и не подрался с ETL за RAM:
<!-- /etc/clickhouse-server/config.d/memory.xml -->
<clickhouse>
<!-- не забирать под сервер больше 60% RAM: рядом работает ETL -->
<max_server_memory_usage_to_ram_ratio>0.6</max_server_memory_usage_to_ram_ratio>
<!-- кэш засечек (primary index marks) -->
<mark_cache_size>5368709120</mark_cache_size> <!-- 5 ГиБ -->
<!-- кэш распакованных блоков -->
<uncompressed_cache_size>8589934592</uncompressed_cache_size> <!-- 8 ГиБ -->
</clickhouse>И ещё одна деталь, которая и даёт «полёт»: max_threads = auto(16). По умолчанию каждый запрос параллелится на все 16 ядер — одинGROUP BY раскладывается на 16 потоков и молотит данные векторно, блоками. Отсюда и сотни миллионов строк в секунду на одной VPS.
6. Два козыря: сжатие и column pruning
Козырь №1 — сжатие 4.8×. 355 ГиБ логических данных превращаются в 74 ГиБ на диске. Колоночное хранение + кодек LZ4: значения одного типа лежат подряд и жмутся кратно лучше, чем перемешанные поля строки. Меньше читать с диска = быстрее запросы. Это ровно то, за что колоночные базы обгоняют строчные на аналитике.
| Метрика | Логически | На диске |
|---|---|---|
| Объём данных ClickHouse | 355 ГиБ | 74 ГиБ |
| Коэффициент сжатия | — | 4.8× |
| Кодек | — | LZ4 (колоночный) |
Козырь №2 — column pruning (читается только нужное). Один и тот же GROUP BY по таблице лотов (31,4 млн строк, 5,9 ГиБ), но с разным набором колонок:
Строчный PostgreSQL в обоих случаях поднимал бы строки целиком — а значит, «дешёвый» запрос на 2 колонки стоил бы ему столько же, сколько «дорогой». В этом и вся разница.
7. Живые бенчмарки
Все замеры — на боевом сервере, во время работающего ETL. Никаких синтетических датасетов, только продовые таблицы. Начнём с классики — годовая динамика по 31,4 млн лотов:
SELECT
toYear(tender_publish_date_day) AS y,
count() AS lots,
round(sum(lot_amount) / 1e9, 1) AS bln_tenge
FROM goszakup_dmrt.lots
GROUP BY y
ORDER BY y DESC;
-- 2025: 3 869 168 лотов / 15 750 млрд ₸
-- 2024: 3 694 027 лотов / 15 910 млрд ₸
-- 2023: 3 910 433 лота / 12 150 млрд ₸
-- ⏱ 0,08 с · 31,4 млн строк · 378 млн строк/сек · 3,9 ГиБ/секДальше — топ-10 заказчиков по сумме лотов. Тут в GROUP BY уходит длинная строка (имя заказчика), поэтому чтение тяжелее, но всё равно доли секунды:
SELECT
customer_name_ru,
round(sum(lot_amount) / 1e9, 0) AS bln_tenge
FROM goszakup_dmrt.lots
GROUP BY customer_name_ru
ORDER BY bln_tenge DESC
LIMIT 10;
-- АО «НК ҚазАвтоЖол» ................. 3 805 млрд ₸
-- КГУ «Управление строительства
-- г. Алматы» ..................... 2 538 млрд ₸
-- МЧС РК ............................. 1 584 млрд ₸
-- ⏱ 0,46 с · 31,4 млн строк · 69 млн строк/секА вот полнотекстовый поиск честным полным сканом — ILIKE '%компьютер%' по 31,4 млн названий лотов, без всякого индекса:
SELECT count()
FROM goszakup_dmrt.lots
WHERE lot_name_ru ILIKE '%компьютер%';
-- 191 310 совпадений
-- ⏱ 0,32 с · полный скан 31,4 млн строк · 98 млн строк/секСводка по пяти боевым запросам — агрегация, top-N по строке, сумма платежей, JOIN двух больших таблиц и полнотекстовый скан:
| Запрос | Строк | Время | Строк/сек |
|---|---|---|---|
| Q1 · агрегация по годам | 31,4 млн | 0,08 с | 378 млн |
| Q2 · top-N по строке | 31,4 млн | 0,46 с | 69 млн |
| Q3 · sum платежей | 11,5 млн | 0,17 с | 66 млн |
| Q4 · JOIN 14,4М × 11,5М | 26 млн | 0,27 с | 95 млн |
| Q5 · ILIKE полный скан | 31,4 млн | 0,32 с | 98 млн |
Пропускная способность по запросам
Млн строк в секунду на одной VPS (16 vCPU), боевые таблицы. Больше — лучше.
Q3 — сумма всех казначейских выплат (11,5 млн платежей → 43,9 трлн ₸) за 0,17 с. Q4 — JOIN 14,4 млн договоров с 11,5 млн платежей за 0,27 с.
Про «холодный» кэш. При самом первом запуске те же запросы шли ~1 секунду (данные ещё не в кэше). После прогрева — десятые доли секунды. Но и в том, и в другом случае это интерактивная аналитика без предрасчёта и без индексов под каждый запрос. Для сравнения: такой же полный скан и GROUP BY в строчной базе на этих объёмах тянулся бы секундами и минутами.
8. Почему это вообще работает — 4 причины
Именно четвёртый пункт и был для меня главной причиной ухода с PostgreSQL в самом пайплайне: ReplacingMergeTree заменил всю возню с INSERT ... ON CONFLICT и блокировками на апдейтах. А общий выигрыш по скорости на аналитике для колоночных баз хорошо известен — они и считаются самыми быстрыми под аналитику именно за счёт трёх множителей: сжатие в 5–10 раз, сокращение I/O на 90%+ на широких таблицах и векторизованное выполнение.
9. Как повторить у себя — просто скопируй промпт
Не обязательно быть дата-инженером. Если у тебя есть данные в PostgreSQL (или обычные csv/excel-файлы) и тормозящая аналитика — просто открой Claude Code (или Cursor) в папке проекта и скопируй промпт ниже. Агент сам поставит ClickHouse, сам перельёт туда данные и покажет, стало ли быстрее. От тебя — один клик «Копировать» и один ответ на вопрос агента, где лежат данные.
Ты — мой дата-инженер. Объясняй всё ПРОСТО, шаг за шагом, без жаргона.
Задача: ускорить мою аналитику, переехав на ClickHouse. Сделай всё сам.
ШАГ 0 — ДАННЫЕ.
Мои данные лежат здесь: <PostgreSQL-строка подключения ИЛИ путь к csv/parquet/xlsx>.
Если я не указал — поищи сам в текущей папке и стандартных местах (Desktop,
Downloads) csv/parquet/xlsx или локальную базу Postgres. Если ничего не нашёл —
просто спроси меня, где данные и что я обычно по ним считаю.
ШАГ 1 — ПОСТАВЬ CLICKHOUSE ЛОКАЛЬНО.
Установи ClickHouse самым простым способом для моей ОС
(на Linux/Mac: curl https://clickhouse.com/ | sh, затем ./clickhouse server;
на Windows — через Docker: docker run -d --name ch -p 8123:8123 -p 9000:9000
clickhouse/clickhouse-server). Проверь, что сервер поднялся, и покажи мне команду
подключения (clickhouse-client).
ШАГ 2 — ПЕРЕЛЕЙ ДАННЫЕ.
Создай таблицу с движком MergeTree под мои данные (сам подбери типы колонок и
разумный ORDER BY — обычно это дата или id). Если данные обновляются по ключу —
используй ReplacingMergeTree вместо UPSERT. Залей мои данные в ClickHouse.
ШАГ 3 — ЗАМЕРЬ «БЫЛО / СТАЛО».
Возьми 3-4 моих типичных аналитических запроса (агрегации, GROUP BY, суммы по
периодам, топ-N, полнотекстовый поиск). Прогони их и в старой базе (если это
Postgres), и в ClickHouse. Замерь время каждого. Покажи размер данных на диске
до и после (у ClickHouse он будет в разы меньше из-за сжатия).
ШАГ 4 — ВЕРДИКT (просто и по-человечески):
• Насколько быстрее стало (во сколько раз), таблицей «запрос / было / стало».
• Сколько сэкономили места на диске.
• Стоит ли мне переезжать на ClickHouse ПОЛНОСТЬЮ или держать его рядом с
Postgres только под аналитику. Ответь прямо: ДА или НЕТ и почему.
ВАЖНО помни: ClickHouse — для аналитики (много чтения, отчёты, дашборды), а НЕ
для транзакций и частых точечных апдейтов — их оставь Postgres. Если данных мало
(меньше пары миллионов строк) — честно скажи, что ClickHouse мне пока не нужен.Ничего не сломается: агент ставит ClickHouse отдельно и копирует данные, а не переносит — твой PostgreSQL остаётся на месте. Хочешь так же, как у меня — в проде на VPS — попроси агента поставить ClickHouse через официальный apt/systemd-способ и настроить max_server_memory_usage_to_ram_ratio под объём RAM сервера.
Итог
Одна VPS за копейки, 16 ядер, ноль шардов — и интерактивная аналитика по сотням миллионов строк госзакупок РК. Для аналитической нагрузки (много чтения, агрегации, полные сканы, редкие точечные апдейты) ClickHouse обходит классический PostgreSQL не на проценты, а в разы — и ещё экономит диск за счёт сжатия.
Но помню и повторю: это OLAP-инструмент. Для транзакций, точечных апдейтов и консистентности каждой записи оставляй PostgreSQL. А если данных реально много и нагрузка аналитическая — бери ClickHouse, накатывай MergeTree-схему слоями, и твоя аналитика тоже полетит. Проверено на 781 млн строк.