Модуль 6. Язык запросов в StarRocks и оптимизация SQL
Методологическое понимание работы с SQL в StarRocks
StarRocks на 100% ориентирован на SQL, причём диалект совместим с MySQL, но дополнен множеством аналитических расширений (Window, Rollup, Bitmap, HLL, JSON-функции и др.).
Методология тут простая:
- Писать запросы под аналитическую нагрузку, а не как в OLTP — избегать ненужных SELECT * и подзапросов без фильтров.
- Помнить, что нет полноценного «вторичного» индекса, значит, фильтры и сортировки должны совпадать с архитектурой таблиц (partition, distribution, sort key).
- Использовать оптимизатор — EXPLAIN и PROFILE должны быть частью процесса разработки запроса.
Ключевые возможности SQL в StarRocks
Базовый синтаксис:
- Совместим с MySQL 5.7+.
- Поддержка JOIN всех типов (INNER, LEFT, RIGHT, FULL OUTER).
- Поддержка подзапросов (subqueries) и CTE (WITH).
Аналитические функции:
- Window: ROW_NUMBER(), RANK(), SUM() OVER (...), LAG(), LEAD().
- ROLLUP / CUBE: многоуровневая агрегация.
- GROUPING SETS: гибкое формирование группировок.
Специализированные типы и функции:
- Bitmap: хранение уникальных значений и быстрые cardinality-запросы.
- HLL (HyperLogLog): быстрые приближённые подсчёты уникальных значений.
- JSON: JSON_PARSE(), JSON_QUERY(), JSON_PATH().
Пример аналитического запроса
WITH weekly_sales AS (
SELECT
region_id,
YEARWEEK(sale_date) AS week_num,
SUM(amount) AS total_sales
FROM sales
WHERE sale_date >= '2025-01-01'
GROUP BY region_id, YEARWEEK(sale_date)
)
SELECT
region_id,
week_num,
total_sales,
RANK() OVER (PARTITION BY week_num ORDER BY total_sales DESC) AS rank_in_week
FROM weekly_sales;
- CTE помогает избежать дублирования агрегации.
- Window позволяет строить рейтинг внутри каждого периода.
- Фильтр по дате сокращает сканируемые партиции.
Оптимизационные приёмы
-
Фильтрация по партициям
- Фильтры по partition-колонке позволяют StarRocks отбрасывать ненужные партиции (partition pruning).
- Пример: WHERE sale_date >= '2025-01-01' при партиционировании по дате.
- Избегать SELECT *
- Выбираем только необходимые поля — это уменьшает I/O и CPU.
- Если BI делает одинаковые тяжёлые агрегации — выносим в материализованное представление.
- Если обе таблицы распределены по одному ключу, shuffle не нужен.
- EXPLAIN → смотрим план.
- PROFILE → видим реальное время и этапы выполнения.
- Предагрегация через MV
- Использовать HASH JOIN по ключам дистрибуции
- Профилирование
Пример оптимизации запроса
До:
SELECT
r.name,
SUM(s.amount)
FROM sales s
JOIN regions r ON s.region_id = r.id
WHERE s.sale_date >= '2025-01-01'
GROUP BY r.name;
Проблема: shuffle по region_id на join, полное сканирование таблицы.
После:
- Дистрибуция и партиционирование sales и regions по region_id.
- Предагрегация в MV:
CREATE MATERIALIZED VIEW mv_sales_region AS SELECT region_id, SUM(amount) AS total_amount FROM sales WHERE sale_date >= '2025-01-01' GROUP BY region_id;
Запрос в BI:
SELECT r.name, m.total_amount FROM mv_sales_region m JOIN regions r ON m.region_id = r.id;
Результат: время ответа сократилось с 12 сек до <1 сек.
Практические кейсы
Кейс 1. Финансовый отчёт
- Проблема: тяжёлые оконные функции для P&L отчётов.
- Решение: предрасчёт cumulative SUM в MV, в BI только фильтрация.
- Риск: MV устаревает при задержках ingestion.
- Защита: инкрементальное обновление.
Кейс 2. Маркетинговая аналитика
- Проблема: BI строит 4 варианта отчёта с разными группировками.
- Решение: GROUPING SETS в одном запросе вместо 4 отдельных.
- Результат: нагрузка на кластер снизилась на 60%.
Кейс 3. IoT-аналитика
- Проблема: уникальные устройства в потоке событий.
- Решение: использование Bitmap для подсчёта уникальных device_id.
- Результат: латентность запросов снизилась с 8 сек до 0,7 сек.
Риски и защита
|
Риск |
Симптом |
Как избежать |
|---|---|---|
|
BI делает сложные join по сырым данным |
Высокая латентность |
Предагрегация в MV |
|
Нет фильтра по партиции |
Скан всей таблицы |
WHERE по partition key |
|
SELECT * |
Лишний I/O |
Выбирать только нужные колонки |
|
Много мелких подзапросов |
План громоздкий |
CTE, MV |
|
Кардинальность ключей в join очень разная |
Перекос нагрузки |
Репликация маленькой таблицы (broadcast join) |
Методологические рекомендации
- Пишите SQL «от партиции» — всегда проверяйте, что фильтры совпадают с partition key.
- Закладывайте MV в архитектуру — BI не должен считать «с нуля».
- Используйте аналитические функции вместо нескольких подзапросов.
- Регулярно профилируйте топ-10 запросов в продакшне.
- Разграничивайте зоны — сырые данные и витрины не должны лежать в одной таблице.




