При всплесках нагрузки: StarRocks Query Cache обеспечивает кратное ускорение
Бывали ли у вас ситуации, когда каждое утро или в часы пиковых активностей множество пользователей заходят в платформы отчётности или аналитические приложения за свежими метриками и трендами? Часто это приводит к лавине схожих агрегирующих запросов по большим наборам данных, росту загрузки CPU кластера и деградации задержек. Можно ли «умно сократить объём вычислений» при такой высокой параллельности запросов? Да — с помощью Query Cache.
01. StarRocks Query Cache (кэш запросов)
Чтобы решить проблему повторных вычислений, StarRocks реализует Query Cache. Он кэширует в памяти локальные промежуточные результаты агрегаций, чтобы переиспользовать их при последующих запросах. При выполнении запроса StarRocks сперва проверяет Query Cache. Если для эквивалентной по семантике операции уже есть кэшированные результаты, движок переиспользует их, избегая повторных чтений и части вычислений, что заметно ускоряет запрос.
Важно: Query Cache — это не Result Cache. Он хранит не финальные результаты, а промежуточные агрегаты, что существенно повышает вероятность попадания в кэш. Благодаря этому Query Cache ускоряет даже не полностью совпадающие запросы. В условиях высокой параллельности он даёт ускорение в 3–17 раз, снижая нагрузку на кластер и удерживая стабильную производительность в пиковые периоды.

02. Максимизация переиспользования кэша: проектирование под реальные сценарии
Query Cache спроектирован так, чтобы кэш максимально переиспользовался в типичных рабочих паттернах. Три ключевых сценария:
Семантически эквивалентные запросы.
Сканирование перекрывающихся партиций: разбиение по предикатам.
Сценарии только с добавлением данных (append), без обновлений и удалений: многоверсионный кэш.
2.1. Семантически эквивалентные запросы


Если два запроса эквивалентны по семантике (даже при различиях в синтаксисе или факторизации подзапросов), результаты агрегаций, кэшированные одним запросом, могут быть использованы другим.
Подробнее: https://docs.starrocks.io/en/latest/using_starrocks/query_cache
2.2. Перекрывающиеся партиции: разбиение по предикатам


Пусть ts — партиционная колонка, а запросы отличаются лишь диапазоном фильтрации по ts с частичным перекрытием. StarRocks нарезает условие по партициям, кэширует промежуточные агрегаты на уровне партиций и при следующем запросе переиспользует результаты для перекрывающихся партиций.
Подробнее: https://docs.starrocks.io/en/latest/using_starrocks/query_cache
2.3. Только добавление данных: многоверсионный кэш
По мере загрузок в Tablet появляются новые версии. Кэшированные результаты могут «отставать» от актуальной версии Tablet. Механизм многоверсионного кэша объединяет кэшированные агрегаты с инкрементальными данными на диске, чтобы новый запрос видел актуальные данные при условии, что изменения — это добавления (append), без обновлений/удалений.
Подробнее: https://docs.starrocks.io/en/latest/using_starrocks/query_cache
03. Где Query Cache особенно эффективен
По сравнению с Result Cache, кэширование промежуточных агрегатов охватывает больше случаев и даёт прирост чаще. Query Cache особенно полезен, когда:
Часто выполняются агрегирующие запросы: по «широким» таблицам и после JOIN в звёздной схеме.
Запросы похожи по семантике и допускают неполное совпадение.
Данные добавляются без обновлений/удалений (append-only).
Типичные сценарии:
Платформы мониторинга и отчётности: объём данных растёт со временем, а пользователи регулярно считают агрегаты по скользящим окнам времени.
Высокопараллельная пользовательская аналитика: сводные метрики по выбранным измерениям.
Результат — переиспользование промежуточных результатов, меньше повторных вычислений, быстрее ответы и лучшая масштабируемость при всплесках параллельности.
04. Лучшие практики по схеме данных и настройкам
Чтобы Query Cache приносил максимум пользы, продумайте схему и настройки:
Выделите отдельную партиционную колонку типа date/datetime. Значения в ней желательно монотонно возрастают с загрузками, а запросы фильтруют по диапазонам этой колонки.
Подберите разумный размер партиций. Последние партиции чаще меняются, что ведёт к инвалидации кэша; слишком крупные или слишком мелкие партиции снижают hit rate.
Держите число бакетов на уровне нескольких десятков. Если бакетов слишком мало и число Tablet, обрабатываемых узлом BE, меньше значения параметра pipeline_dop, Query Cache может не сработать.
Архитектурная заметка:
На каждом узле BE поддерживается локальный кэш. Если на узле BE есть нужная реплика, запрос может быть направлен туда. Чтобы кэш успел наполниться и широко переиспользоваться, имеет смысл, чтобы запрос выполнялся как минимум столько раз, сколько реплик (replication_num). Однако Query Cache не требует полной предварительной «прогрузки», чтобы начать давать эффект.
05. Как включить и проверить Query Cache (пример)
5.1. Подготовка
По умолчанию Query Cache выключен. Включите его параметром сессии. В примере ниже — кластер с одним узлом BE и одной репликой; чтобы Query Cache сработал, устанавливаем pipeline_dop=1. Для диагностики включим Query Profile.
-- Включить Query Cache
SET enable_query_cache = true;
-- Одна реплика → установим pipeline_dop = 1
SET pipeline_dop = 1;
-- Включить Query Profile
SET is_report_success = true;
SET enable_profile = true;
DDL и загрузка данных:
https://docs.starrocks.io/en/3.1/using_starrocks/query_cache
5.2. Пробные запросы
Сначала выполним базовый запрос:
-- Q1: базовый запрос
SELECT
date_trunc('hour', ts) AS hour,
k0,
SUM(v1) AS __c_0
FROM t0
WHERE ts BETWEEN '2022-01-03 00:00:00' AND '2022-01-03 23:59:59'
GROUP BY
date_trunc('hour', ts),
k0;
Проверим состояние кэша на узле BE:
curl http://127.0.0.1:8040/api/query_cache/stat
Пример ответа (видно, что кэш заполняется — usage > 0):
{
"capacity": 536870912,
"usage": 3889,
"usage_ratio": 0.000007243826985359192,
"lookup_count": 42,
"hit_count": 0,
"hit_ratio": 0.0
}
Теперь выполним семантически эквивалентный запрос:
-- Q2: семантически эквивалентный запрос
SELECT
(
IFNULL(SUM(murmur_hash3_32(hour)), 0)
+ IFNULL(SUM(murmur_hash3_32(k0)), 0)
+ IFNULL(SUM(murmur_hash3_32(__c_0)), 0)
) AS fingerprint
FROM (
SELECT
date_trunc('hour', ts) AS hour,
k0,
SUM(v1) AS __c_0
FROM t0
WHERE ts BETWEEN '2022-01-03 00:00:00' AND '2022-01-03 23:59:59'
GROUP BY
date_trunc('hour', ts),
k0
) AS t;
Снова смотрим статистику:
curl http://127.0.0.1:8040/api/query_cache/stat
Пример ответа (есть попадания — hit_count > 0, hit_ratio > 0):
{
"capacity": 536870912,
"usage": 3889,
"usage_ratio": 0.000007243826985359192,
"lookup_count": 44,
"hit_count": 2,
"hit_ratio": 0.045454545454545459
}
В Query Profile появится узел плана Cache. При попадании показатели Populate равны нулю, а чтение «сырых» строк на Scan может быть нулевым:
CachePopulateBytes: 0.00
CachePopulateChunkNum: 0
CachePopulateRowNum: 0
CachePopulateTabletNum: 0
И на Scan:
RawRowsRead: 0M (0)
06. Отчёт о производительности
Хотя Query Cache — это не Result Cache, переиспользование промежуточных результатов даёт значительный выигрыш, в том числе и для запросов с JOIN. Для простоты ниже приводится отношение задержек no_cache/cache_hit (RT).
Примечание: во всех тестах ниже Query Cache предварительно заполнен.
6.1. «Широкая» таблица
Конфигурация: 3 × (CPU: 16 cores, RAM: 64 GB)
Набор данных: SSB 100 GB, широкая таблица
Параллельность: 10

Результат: при 10 параллельных запросах и однотабличной агрегации попадание в Query Cache даёт до 10× ускорения.
6.2. Звёздная схема (многотабличные запросы)
Конфигурация: 3 × (CPU: 16 cores, RAM: 64 GB)
Набор данных: SSB 100 GB, несколько таблиц
Параллельность: 10

Результат: при 10 параллельных запросах и многотабличной агрегации попадание в Query Cache даёт до 17× ускорения.
07. Итоги
Query Cache существенно ускоряет агрегирующие запросы: хранит локальные промежуточные результаты в памяти, сокращает повторные чтения и вычисления для новых запросов, похожих на уже выполненные, и гибче, чем Result Cache, поскольку ускоряет и не полностью одинаковые запросы. В условиях высокой параллельности — когда многие пользователи запускают схожие запросы по большим наборам — Query Cache экономит ресурсы, ускоряет ответы и улучшает масштабируемость системы.
Проверка попаданий и диагностика
Проверить состояние кэша на узле BE:
curl http://127.0.0.1:8040/api/query_cache/stat
Смотрите на метрики: usage, lookup_count, hit_count, hit_ratio.
Понять, что запрос попал в кэш:
В статистике растут lookup_count и hit_count.
В Query Profile есть узел плана Cache; показатели CachePopulate* равны 0 при hit.
На Scan RawRowsRead может быть 0 при полном попадании.
Если Query Cache «не срабатывает»:
Убедитесь, что enable_query_cache = true в вашей сессии.
Проверьте, что pipeline_dop согласован с количеством доступных Tablet/реплик; при слишком малом числе Tablet относительно pipeline_dop кэш может не активироваться.
Убедитесь в семантической эквивалентности запросов или наличии перекрывающихся партиций.
Частые обновления/удаления в горячих партициях приводят к инвалидации кэша — настройте партиционирование так, чтобы повысить стабильность кэша.
Сообщество и ресурсы
Тред сообщества по Query Cache (вопросы, опыт, диагностика):
https://forum.mirrorship.cn/t/topic/8468Документация по Query Cache:
https://docs.starrocks.io/en/latest/using_starrocks/query_cacheОбщее введение в StarRocks:
https://docs.starrocks.io/en/docs/introduction/StarRocks_intro/