StarRocks против ClickHouse: архитектура и выбор СУБД для аналитики нормализованных данных

StarRocks против ClickHouse: архитектура и выбор СУБД для аналитики нормализованных данных

 

Инженеры данных часто спорят, какая колоночная СУБД быстрее. Спор бессмысленный без контекста нагрузки. ClickHouse и StarRocks решают разные задачи, хотя обе относятся к классу аналитических OLAP-движков. В этой статье мы разберем их архитектуру, покажем разницу в обработке соединений таблиц и соберем локальный стенд для честного нагрузочного теста на нормализованной схеме.

Материал рассчитан на дата-инженеров, которые проектируют корпоративное хранилище и выбирают движок под конкретный профиль запросов. Мы поднимем оба кластера в Docker, сгенерируем синтетический датасет на десятки гигабайт и сравним время выполнения многотабличных JOIN запросов вместе с потреблением оперативной памяти.

Чем отличается StarRocks vs. ClickHouse

ClickHouse это колоночная аналитическая СУБД с открытым исходным кодом, созданная в Яндексе для обработки событийных данных. Ее сильная сторона это сканирование плоских широких таблиц с миллиардами строк. Актуальная линейка на июль 2026 года это релиз 26.6, а версия 26.3 имеет статус долгосрочной поддержки LTS. Движок использует семейство таблиц MergeTree и агрессивно оптимизирован под последовательное чтение с диска. Подробный разбор движка собран в нашей вики-статье про ClickHouse.

StarRocks это MPP-СУБД для real-time аналитики, форк проекта Apache Doris, развиваемый как отдельный продукт. Актуальная стабильная версия это 4.1.1, вышедшая в конце мая 2026 года, а ветка 3.5 остается популярным выбором для продакшена. Ключевое отличие StarRocks это встроенный стоимостный оптимизатор и эффективное распределенное выполнение соединений прямо в движке, без предварительной денормализации данных. Базовые понятия движка мы разобрали в вики-статье про StarRocks.

 

Проектирование Online-хранилищ данных на StarRocks.

Код курса
STAR
Ближайшая дата курса
7 сентября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

Архитектура MPP и векторизация запросов

Обе базы применяют колоночное хранение и векторизацию вычислений. Это значит, что данные обрабатываются пакетами по несколько тысяч значений, а не построчно. Такой подход задействует SIMD-инструкции процессора и заметно ускоряет агрегации. На этом сходство заканчивается, дальше идут архитектурные развилки.

ClickHouse исторически строился вокруг идеи одной большой таблицы. Каждый шард обрабатывает свой кусок данных почти независимо. Распределенные соединения между шардами возможны, но требуют аккуратной ручной настройки. Классический рецепт для ClickHouse это заранее денормализовать данные и хранить готовую широкую таблицу, где все нужные атрибуты уже склеены.

StarRocks с самого начала проектировался как массово-параллельная система с полноценным обменом данными между узлами. Архитектура делится на фронтенды FE, которые хранят метаданные и строят план запроса, и бэкенды BE, которые выполняют вычисления. Узлы умеют перераспределять промежуточные результаты по сети через операцию shuffle. Именно это позволяет соединять несколько крупных таблиц без предварительного объединения.

Архитектура MPP StarRocks FE BE против шардов ClickHouse

 

Как базы обрабатывают соединения таблиц

Соединение таблиц это главная точка расхождения двух движков. Здесь важно понимать, что делает планировщик до начала чтения данных. От выбранной стратегии зависит и время ответа, и пиковое потребление памяти.

ClickHouse опирается на правила. Порядок соединения задается тем, как разработчик написал запрос. По умолчанию правая таблица целиком загружается в оперативную память в виде хэш-таблицы, это hash join. Если правая таблица большая, движок упирается в лимит памяти и запрос падает с ошибкой. Частичным решением служат словари в оперативной памяти или движок Join, но это ручная и хрупкая оптимизация.

StarRocks опирается на статистику. Стоимостный оптимизатор CBO сам оценивает кардинальность таблиц по гистограммам распределения и выбирает порядок соединения. Движок динамически переключается между стратегиями broadcast, shuffle и colocate в зависимости от размеров данных. Runtime Filter отсекает лишние строки правой таблицы еще до соединения. В результате нормализованная схема с тремя или четырьмя таблицами выполняется без денормализации.

Различия удобно свести в таблицу, чтобы держать компромиссы перед глазами при выборе движка.

Характеристика ClickHouse 26.x StarRocks 4.1
Модель планировщика По правилам, порядок задает автор запроса Стоимостный оптимизатор CBO по статистике
Распределенный JOIN Ограничен, требует ручной настройки Нативный shuffle между BE-узлами
Типовой рецепт Денормализация в широкую таблицу Работа по нормализованной схеме
Реакция на большую правую таблицу Риск переполнения памяти Runtime Filter и смена стратегии
Сильная ниша Плоские таблицы, логи, кликстрим Схемы со звездой и снежинкой, ad-hoc BI

Границы применимости двух движков

Универсальной кнопки не существует. Каждый движок хорош в своей нише, и грамотный инженер держит в арсенале оба. Ниже собраны практические ориентиры, когда какой инструмент уместнее.

  • ClickHouse забирает задачи с плоскими широкими таблицами. Это логи, метрики, кликстрим и события, где данные уже пришли в денормализованном виде и запросы сканируют одну таблицу.
  • StarRocks забирает корпоративную аналитику со сложными связями. Это схемы со звездой, витрины BI и ситуации, где денормализация слишком дорога или невозможна из-за постоянных обновлений.

Таким образом, выбор движка это не вопрос моды, а вопрос профиля нагрузки. Дальше мы соберем стенд и проверим эти тезисы измерениями, а не на словах.

Практическое задание для сравнения StarRocks vs ClickHouse

 

По традиции весь код используемый в статье выкладываем на наш GitHub репозиторий
StarRocks vs. ClickHouse: сравнение архитектур для аналитики from airflow import DAG from airflow.operators.bash import BashOperator from datetime import datetime with DAG( dag_id="spark_submit_demo", start_date=datetime(2025, 1, 1), schedule="@daily", catchup=False ) as dag: run = BashOperator( task_id="run_job", bash_command="spark-submit app.py" ) GitHub code example StarRocks vs. ClickHouse: сравнение архитектур для аналитики

Конфигурация Docker Compose для локального стенда

Минимальные ресурсы для полноценного теста: 8 ядер, 16 ГБ RAM и 70 ГБ свободного диска. StarRocks в режиме allin1 требователен к памяти, ClickHouse скромнее. Для теста поднимем оба кластера в одном файле. StarRocks запускается через образ allin1, который совмещает FE и BE в одном контейнере. ClickHouse стартует из официального серверного образа. Версии зафиксированы в тегах образов, это важно для воспроизводимости результатов.

# Проверено для StarRocks 3.5.0 и ClickHouse 26.3 LTS
# ВАЖНО. Перед первым запуском на хосте задать параметр ядра, иначе BE-нода StarRocks упадёт:
# sudo sysctl -w vm.max_map_count=2000000
# echo 'vm.max_map_count=2000000' | sudo tee /etc/sysctl.d/99-starrocks.conf
# Контейнеру allin1 нужно минимум 3-4 ГБ свободной RAM, первый старт FE занимает до 90 секунд.
services:
  starrocks:
    image: starrocks/allin1-ubuntu:3.5.0
    container_name: starrocks
    ports:
      - "9030:9030"   # MySQL-протокол для FE
      - "8030:8030"   # HTTP FE
      - "8040:8040"   # HTTP BE
    ulimits:
      nofile:
        soft: 65535
        hard: 65535
  clickhouse:
    image: clickhouse/clickhouse-server:26.3
    container_name: clickhouse
    ports:
      - "8123:8123"   # HTTP
      - "9000:9000"   # нативный протокол
    environment:
      CLICKHOUSE_USER: admin
      CLICKHOUSE_PASSWORD: Str0ngPass
      CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    volumes:
      - ./data/clickhouse:/var/lib/clickhouse

Запуск стенда сводится к одной команде в каталоге с файлом. После старта StarRocks доступен по порту 9030 через любой MySQL-клиент (логин root без пароля), а ClickHouse отвечает на порту 9000 с логином: admin и паролем Str0ngPass.

# протестировано для Docker Compose v2.27
docker compose up -d
docker compose ps
# подключение к StarRocks
mysql -h 127.0.0.1 -P 9030 -u root
# подключение к ClickHouse
clickhouse-client --host 127.0.0.1 --port 9000

 

Подготовка демо кластера для работы с Docker и тестовым датасетом

В Ubuntu 24.04 уже стоит Python 3.12. Доставляем pip и модуль venv на всякий случай.

sudo apt install -y python3 python3-pip python3-venv
python3 --version

Важный нюанс про venv. Наш генератор датасета использует только стандартную библиотеку Python и не требует установки пакетов через pip. Поэтому виртуальное окружение для него не обязательно. Но в Ubuntu 24.04 действует правило PEP 668: системный pip запрещает ставить пакеты глобально, чтобы не сломать систему. Если в будущих статьях понадобятся внешние библиотеки, например kafka-python или faker, создавайте venv.

# создать окружение в каталоге проекта
python3 -m venv .venv
# активировать
source .venv/bin/activate
# теперь pip ставит пакеты только внутрь окружения
pip install --upgrade pip


# пример установки библиотеки
# pip install kafka-python
# для выхода  из окружения
deactivate

 

Генерация синтетического датасета на 10-20 ГБ

Чтобы разница между движками стала заметной, нужна нормализованная схема транзакционной системы. Возьмем классику интернет-магазина, где есть клиенты, товары, заказы и позиции заказов. Скрипт на Python генерирует четыре CSV-файла с настраиваемым числом строк. Для объема около 18 ГБ достаточно порядка 400 миллионов позиций заказов. Объем регулируется параметром scale. Внешних библиотек нет. Время генерации примерно 20 минут.

Файл article01/generate_dataset.py.

# протестировано для Python 3.12
# Генератор нормализованного датасета интернет-магазина: customers, products, orders, order_items.
#
# Объём задаётся параметром --scale (множитель базового набора).
#   scale 1  -> примерно 4.4 ГБ   (100 млн позиций)  быстрый прогон
#   scale 3  -> примерно 13 ГБ    (300 млн позиций)
#   scale 4  -> примерно 18 ГБ    (400 млн позиций)  полноценный нагрузочный тест
# Для мгновенной проверки схемы возьмите --scale 0.01 (примерно 45 МБ).
#
# Запуск:
#   python3 generate_dataset.py --scale 1 --out dataset
#
import csv
import random
import os
import argparse
from datetime import date, timedelta

BASE_CUSTOMERS = 5_000_000
BASE_PRODUCTS = 500_000
BASE_ORDERS = 40_000_000
BASE_ITEMS = 100_000_000

SIGNUP_START = date(2023, 1, 1)
ORDER_START = date(2024, 1, 1)
STATUSES = ["paid", "shipped", "cancelled"]


def log(msg):
    print(msg, flush=True)


def gen_customers(path, n):
    log(f"customers: {n:,} строк ...")
    with open(path, "w", newline="") as f:
        w = csv.writer(f, lineterminator="\n")  # важно: \n, иначе StarRocks оставит \r в последней колонке
        for cid in range(1, n + 1):
            signup = SIGNUP_START + timedelta(days=random.randint(0, 900))
            w.writerow([cid, f"customer_{cid}", random.randint(1, 90), signup])


def gen_products(path, n):
    log(f"products: {n:,} строк ...")
    with open(path, "w", newline="") as f:
        w = csv.writer(f, lineterminator="\n")  # важно: \n, иначе StarRocks оставит \r в последней колонке
        for pid in range(1, n + 1):
            price = round(random.uniform(1, 5000), 2)
            w.writerow([pid, f"product_{pid}", random.randint(1, 200), price])


def gen_orders(path, n, n_customers):
    log(f"orders: {n:,} строк ...")
    with open(path, "w", newline="") as f:
        w = csv.writer(f, lineterminator="\n")  # важно: \n, иначе StarRocks оставит \r в последней колонке
        for oid in range(1, n + 1):
            odate = ORDER_START + timedelta(days=random.randint(0, 550))
            w.writerow([oid, random.randint(1, n_customers), odate, random.choice(STATUSES)])
            if oid % 5_000_000 == 0:
                log(f"  orders {oid:,}")


def gen_items(path, n, n_orders, n_products):
    log(f"order_items: {n:,} строк ...")
    with open(path, "w", newline="") as f:
        w = csv.writer(f, lineterminator="\n")  # важно: \n, иначе StarRocks оставит \r в последней колонке
        for iid in range(1, n + 1):
            w.writerow([iid, random.randint(1, n_orders), random.randint(1, n_products), random.randint(1, 10)])
            if iid % 10_000_000 == 0:
                log(f"  order_items {iid:,}")


def main():
    ap = argparse.ArgumentParser(description="Генератор датасета для стенда StarRocks vs ClickHouse")
    ap.add_argument("--scale", type=float, default=1.0, help="множитель объёма, 1.0 это примерно 4.4 ГБ")
    ap.add_argument("--out", default="dataset", help="каталог для CSV")
    ap.add_argument("--seed", type=int, default=42, help="seed для воспроизводимости")
    args = ap.parse_args()

    random.seed(args.seed)
    os.makedirs(args.out, exist_ok=True)

    n_customers = max(1, int(BASE_CUSTOMERS * args.scale))
    n_products = max(1, int(BASE_PRODUCTS * args.scale))
    n_orders = max(1, int(BASE_ORDERS * args.scale))
    n_items = max(1, int(BASE_ITEMS * args.scale))

    log(f"scale={args.scale}, каталог={args.out}")
    gen_customers(os.path.join(args.out, "customers.csv"), n_customers)
    gen_products(os.path.join(args.out, "products.csv"), n_products)
    gen_orders(os.path.join(args.out, "orders.csv"), n_orders, n_customers)
    gen_items(os.path.join(args.out, "order_items.csv"), n_items, n_orders, n_products)

    total = sum(os.path.getsize(os.path.join(args.out, f)) for f in os.listdir(args.out))
    log(f"готово. Суммарный объём: {total / 1e9:.2f} ГБ")


if __name__ == "__main__":
    main()

Скрипт пишет данные потоково и не держит их в памяти. Объем регулируется константами в начале файла. Для быстрой проверки уменьшите числа в десять раз, для полноценного нагрузочного теста оставьте как есть —scale 4.

 

Создаем скрипты DDL и DCL скрипты для обеих баз StarRocks и ClickHouse

Схема одинаковая по смыслу, но синтаксис создания таблиц различается. В StarRocks мы указываем модель таблицы и ключ распределения по бакетам. В ClickHouse задаем движок MergeTree и ключ сортировки. Ниже приведены DDL для StarRocks.

-- протестировано для StarRocks 3.5.0
CREATE DATABASE shop;
USE shop;

CREATE TABLE customers (
    customer_id BIGINT,
    name        VARCHAR(64),
    region_id   INT,
    signup_date DATE
) DUPLICATE KEY(customer_id)
DISTRIBUTED BY HASH(customer_id) BUCKETS 16;

CREATE TABLE products (
    product_id  BIGINT,
    name        VARCHAR(64),
    category_id INT,
    price       DECIMAL(10,2)
) DUPLICATE KEY(product_id)
DISTRIBUTED BY HASH(product_id) BUCKETS 16;

CREATE TABLE orders (
    order_id    BIGINT,
    customer_id BIGINT,
    order_date  DATE,
    status      VARCHAR(16)
) DUPLICATE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 48;

CREATE TABLE order_items (
    item_id    BIGINT,
    order_id   BIGINT,
    product_id BIGINT,
    quantity   INT
) DUPLICATE KEY(item_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 96;

Аналогичная схема в ClickHouse использует движок MergeTree. Ключ сортировки выбран так, чтобы ускорить JOIN по идентификатору заказа (Примечание: это не гарантирует правильную работа фильтра при выборке).

-- протестировано для ClickHouse 26.3 LTS
CREATE DATABASE shop;

CREATE TABLE shop.customers (
    customer_id UInt64,
    name        String,
    region_id   UInt16,
    signup_date Date
) ENGINE = MergeTree ORDER BY customer_id;

CREATE TABLE shop.products (
    product_id  UInt64,
    name        String,
    category_id UInt16,
    price       Decimal(10,2)
) ENGINE = MergeTree ORDER BY product_id;

CREATE TABLE shop.orders (
    order_id    UInt64,
    customer_id UInt64,
    order_date  Date,
    status      String
) ENGINE = MergeTree ORDER BY order_id;

CREATE TABLE shop.order_items (
    item_id    UInt64,
    order_id   UInt64,
    product_id UInt64,
    quantity   UInt32
) ENGINE = MergeTree ORDER BY order_id;

 

Построение DWH на ClickHouse

Код курса
CLICH
Ближайшая дата курса
12 октября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Заливаем данные в таблицы StarRocks и ClickHouse с помощью скрипта

Скрипт заливает четыре файла в StarRocks через Stream Load по HTTP и в ClickHouse через INSERT. Для каждой таблицы задается свой список колонок.

Создаем файл скрипта article01/load.sh и запускаем на исполнение

#!/usr/bin/env bash
# протестировано для StarRocks 3.5.0 и ClickHouse 26.3 LTS
set -e
CH_PASS=Str0ngPass

# StarRocks Stream Load через HTTP на FE, порт 8030
for t in customers products orders order_items; do
  case $t in
    customers)   COLS="customer_id,name,region_id,signup_date" ;;
    products)    COLS="product_id,name,category_id,price" ;;
    orders)      COLS="order_id,customer_id,order_date,status" ;;
    order_items) COLS="item_id,order_id,product_id,quantity" ;;
  esac
  echo "StarRocks load ${t} ..."
  curl --location-trusted -u root: \
    -H "column_separator:," \
    -H "columns:${COLS}" \
    -T "dataset/${t}.csv" \
    "http://127.0.0.1:8030/api/shop/${t}/_stream_load"
  echo
done

# ClickHouse вставка из файлов через клиент в контейнере
for t in customers products orders order_items; do
  echo "ClickHouse load ${t} ..."
  docker exec -i clickhouse clickhouse-client --user admin --password "${CH_PASS}" \
    --query "INSERT INTO shop.${t} FORMAT CSV" < "dataset/${t}.csv"
done

echo "load complete"

Проверяем созданные таблицы на количество записей в StarRocks и ClickHouse. Дополнительно для ClickHouse сразу после вставки надо выполнить оптимизацию parts для всех таблиц, чтобы оптимизировать количество parts и физическую сортировку при записи с помощью optimize table shop.table_name final;

Проверяем размер таблиц на диске для ClickHouse, включая количество строк и сжатие

SELECT
    table,
    sum(rows)                                    AS rows,
    formatReadableSize(sum(data_compressed_bytes))   AS compressed,
    formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed,
    count()                                      AS parts
FROM system.parts
WHERE database='shop' AND active
GROUP BY table ORDER BY table;

Оптимизация таблиц в Clickhouse для уменьшения количества parts и сжатия и упорядочивая записей

В StarRocks перед запуском полезно собрать статистику, чтобы CBO построил корректный план. Одна команда обновляет гистограммы по всем таблицам схемы.

-- протестировано для StarRocks 3.5.0
ANALYZE TABLE order_items;
ANALYZE TABLE orders;
ANALYZE TABLE customers;
ANALYZE TABLE products;

 

Переходим к тестированию: SQL-запрос с четырьмя JOIN операциями

Теперь главное. Возьмем аналитический запрос, который соединяет все четыре таблицы. Он считает выручку по регионам и категориям товаров за последний квартал. Это типичный ad-hoc запрос BI-системы по нормализованной схеме, тот самый сценарий, где расходятся пути двух движков.

-- одинаковый смысл для StarRocks и ClickHouse
SELECT
    c.region_id,
    p.category_id,
    SUM(oi.quantity * p.price) AS revenue,
    COUNT(DISTINCT o.order_id) AS orders_cnt
FROM order_items oi
JOIN orders   o  ON oi.order_id = o.order_id
JOIN customers c ON o.customer_id = c.customer_id
JOIN products  p ON oi.product_id = p.product_id
WHERE o.order_date >= '2025-04-01'
  AND o.status = 'paid'
GROUP BY c.region_id, p.category_id
ORDER BY revenue DESC
LIMIT 50;

Сначала для чистоты эксперимента погасим StarRocks ( docker stop starrocks)  и запустим скрипт в Dbeaver (статистика исполнения показана ниже в Dbeaver и CLI)

Исполнение запроса Join 4 таблиц в ClickHouse

В примере ниже, вы видите пиковое потребление памяти на уровне 5Gb, но при повторном выполнении запроса каждый раз падал, с ошибкой OOM c превышением выше 20 Gb. Стоит сразу оговориться, что задача для ClickHouse и StarRocks  для оптимального выполнения, должна быть сформулирована и реализована по разному, учитывая особенности распределения и процессинга.

Статистика выполнения тестового запроса в ClickHouse

 

Построение DWH на ClickHouse

Код курса
CLICH
Ближайшая дата курса
12 октября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Пример выполнения запроса с падением по ООМ. ClickHouse упёрся в память на JOIN четырёх таблиц (пик 20 ГБ, машина отдала максимум ~21 ГБ) и умер с MEMORY_LIMIT_EXCEEDED. Причина архитектурная: ClickHouse строит хэш-таблицу правой стороны соединения целиком в оперативке, а тут справа большие orders (~160 млн строк), вот RAM и кончилась.

Неоптимальное выполнение JOIN операций в ClickHouseЧтобы запрос всё-таки выполнился, нужно заставить ClickHouse сбрасывать данные на диск. Выполни в той же вкладке перед запросом.

SET join_algorithm = 'grace_hash';
SET max_bytes_before_external_group_by = 2000000000;
SET max_bytes_before_external_sort = 2000000000;

Кроме того фильтры в запросе не оптимизированы под дизайн данных таблиц в ClickHouse, приходите к нам на курс и мы подробно разберем в чем здесь дело и как заставить его не уступать StarRocks в данном кейсе.

 

Теперь тестируем под StarRocks —  SQL-запрос с четырьмя JOIN операциями

Для начала гасим ClickHouse и поднимаем StarRocks и не забываем обновить статистику для таблиц

Отработка JOIN в StarRocks

для выборки 50 значений StarRocks показывает примерно одинаковый результат менее 10 секунд. Проверив план исполнения через EXPLAIN ANALYZE получаем

Полный план исполнения StarRocks JOINузел HASH_JOIN (ID=8) занял 6.7 секунды из 9.5, почти всё время ушло на поиск по хэш-таблице. Пиковая память при этом держалась около 3 ГБ на инстанс, потому что все build-стороны маленькие: отфильтрованные заказы, 2 млн товаров и 20 млн клиентов. Тот же запрос, на котором ClickHouse уперся в 20 ГБ и упал, StarRocks посчитал за секунды и без переполнения, не прибегая к денормализации. Разницу дал CBO (стоимостный оптимизатор), который сам выбрал порядок соединений и распределил их по узлам.

Explain Analyze для StarRocks HASH Join большой таблицы

По цифрам видно, где именно тратится время:

  • BuildTime 84 мс это построение хэша по 9.19 млн заказов, дёшево, потому что таблица маленькая.
  • ProbeTime 6.4 секунды это прогон всех 400 млн order_items через этот хэш, дорого из-за объёма.
  • SearchHashTableTime 5.55 секунды это чистый поиск по хэш-таблице, основная часть probe. Именно поиск совпадений по 400 млн строк и есть узкое место.
  • OutputRows 22.98 млн это сколько строк прошло соединение, то есть позиции, относящиеся к оплаченным заказам за квартал.

Здесь JOIN склеивает позиции заказов с самими заказами. То, что build крошечный, а probe большой, и есть причина, почему StarRocks не ест память. У ClickHouse на этом же месте в хэш попадала большая сторона, поэтому там был OOM. PeakMemory тут в прочерке, это особенность allin1, реальную память можно взять из  аудит-лога по MemCostBytes.

Подробный анализ hash JOIN для StarRocks
Это второй по тяжести блок, 3 секунды из 9.5, то есть ещё 16% времени. Здесь StarRocks агрегирует результат соединения, считает выручку и уникальные заказы, превращаz 23 млн склеенных позиций в предварительные агрегаты по заказам, а дорогой он потому, что COUNT DISTINCT заставляет держать группировку по order_id.

 

Проектирование Online-хранилищ данных на StarRocks.

Код курса
STAR
Ближайшая дата курса
7 сентября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

Сравнительная таблица времени выполнения и памяти

Ниже приведены реальные замеры на стенде с восемью ядрами и примерно 24 ГБ оперативной памяти. Датасет это scale 4, то есть 400 млн позиций заказов, 160 млн заказов, 20 млн клиентов и 2 млн товаров. Запрос один и тот же для обеих баз, без ручного тюнинга.

Сценарий ClickHouse 26.3 StarRocks 3.5
Итог запроса Падение с MEMORY_LIMIT_EXCEEDED 50 строк, успешно
Время обрыв на 14 сек 9.7 сек
Пиковая память запроса 20.2 ГБ, упор в лимит сервера около 3 ГБ на инстанс
Что сделал оптимизатор     построил хэш из 400 млн промежуточных строк отфильтровал orders до 9.19 млн и сделал их build-стороной

Разница именно в плане. ClickHouse строит хэш-таблицу правой стороны соединения, а порядок джойнов берет из текста запроса. В итоге на build-сторону попадают разрастающиеся промежуточные результаты фактов, и память сервера кончается. StarRocks через стоимостный оптимизатор видит селективный фильтр, сжимает orders с 160 млн до 9.19 млн строк, ставит их build-стороной и распределяет соединение по узлам. Тот же запрос доезжает за секунды и без переполнения памяти.

ClickHouse можно заставить выполнить этот запрос вручную. Помогает переключение на дисковый алгоритм соединения через настройку join_algorithm в значение grace_hash, либо переписывание запроса с предварительной фильтрацией orders в подзапросе. Но это ручная работа инженера, тогда как StarRocks делает ту же оптимизацию сам.

 

Заключение и выбор инструмента

Универсальной кнопки не существует, и это главный тезис статьи. ClickHouse остается стандартом де-факто для плоских широких таблиц, логов и кликстрима. StarRocks забирает нишу аналитики со сложными связями, где денормализация слишком дорога. Зрелый дата-инженер умеет работать с обоими движками и выбирает под профиль нагрузки, а не под хайп.

Если ваша задача это кликстрим и событийная аналитика, разобраться в тонкостях MergeTree и оптимизации поможет курс ClickHouse для аналитиков данных и построение DWH. Если же вы строите корпоративное хранилище по нормализованной схеме и потоковую аналитику реального времени, посмотрите новый трек Проектирование и разработка Online-хранилищ данных на StarRocks, Kafka и Flink. На стендах обоих курсов мы разбираем десятки реальных планов выполнения и учим выбирать движок осознанно. Обсудить эти технологии вживую можно на митапе Школы Больших Данных.

Референсные ссылки