Query Result Cache
Некоторые тяжёлые аналитические запросы выполняются снова и снова с теми же результатами: дашборды, регулярные отчёты, повторяющиеся агрегации. Для таких сценариев ClickHouse предоставляет Query Result Cache — server-side кеширование результатов SELECT-запросов. При повторном запросе с идентичным SQL кешированный результат возвращается без обращения к данным.
Поток данных с Query Result Cache
Включение Query Result Cache
Кеш включается на уровне конкретного запроса через SETTINGS:
-- Включить кеш для конкретного запроса
SELECT
toStartOfDay(event_time) AS day,
count() AS events
FROM user_events
WHERE event_time >= now() - INTERVAL 7 DAY
GROUP BY day
ORDER BY day
SETTINGS use_query_cache = 1;
Или на уровне сессии для всех последующих запросов:
-- Включить кеш для всей сессии
SET use_query_cache = 1;
-- Теперь все SELECT запросы в этой сессии кешируются
SELECT count() FROM large_table;
SELECT sum(revenue) FROM orders WHERE date = '2026-01-01';
Инспекция кеша
-- Посмотреть текущее содержимое кеша
SELECT
query,
formatReadableSize(result_size) AS size,
stale,
shared,
expires_at,
key_hash
FROM system.query_cache
ORDER BY expires_at DESC;
Поле stale указывает, что данные могли устареть (INSERT в исходную таблицу). expires_at — когда запись будет автоматически удалена из кеша.
Мониторинг hits/misses
-- Проверить эффективность кеша
SELECT event, value
FROM system.events
WHERE event LIKE 'QueryCache%';
-- Ожидаемый вывод:
-- QueryCacheHits 1523
-- QueryCacheMisses 47
Высокое соотношение QueryCacheHits / QueryCacheMisses указывает на эффективное использование кеша. Если Misses не уменьшаются — возможно, запросы используют non-deterministic функции (см. предупреждение ниже).
Ограничение: non-deterministic функции
Query result cache не работает для запросов с non-deterministic функциями: now(), today(), rand(), currentUser(), generateUUIDv4(). ClickHouse не кеширует такие запросы — результат может меняться между вызовами. При использовании SELECT now(), count() FROM t SETTINGS use_query_cache=1 вы увидите, что QueryCacheMisses продолжает расти при каждом выполнении.
Обходное решение: вычисляйте временные границы вне запроса или используйте явные значения:
-- Не кешируется: now() non-deterministic
SELECT count() FROM events
WHERE event_time >= now() - INTERVAL 1 HOUR
SETTINGS use_query_cache = 1;
-- Кешируется: явные значения
SELECT count() FROM events
WHERE event_time >= '2026-04-17 10:00:00'
AND event_time < '2026-04-17 11:00:00'
SETTINGS use_query_cache = 1;
Настройки Query Result Cache
| Настройка | По умолчанию | Описание |
|---|---|---|
query_cache_max_size_in_bytes | 1 GiB | Максимальный размер всего кеша в памяти |
query_cache_max_entries | 1024 | Максимальное число кешированных результатов |
query_cache_min_query_duration | 0 | Минимальная длительность запроса для кеширования (мс) |
query_cache_min_query_runs | 0 | Минимальное число выполнений перед кешированием |
query_cache_ttl | 60 | TTL кешированного результата (секунды) |
Пример разумной конфигурации для дашборда:
-- Кешировать только запросы дольше 500 мс, TTL 5 минут
SELECT count(), sum(revenue)
FROM orders
WHERE date >= today() - 30
SETTINGS
use_query_cache = 1,
query_cache_min_query_duration = 500,
query_cache_ttl = 300;
Инвалидация кеша
Кеш автоматически инвалидируется при INSERT в исходную таблицу:
-- Кешируем результат
SELECT count() FROM orders SETTINGS use_query_cache = 1;
-- После INSERT в orders кеш автоматически помечается как stale
INSERT INTO orders VALUES (...);
-- Следующий запрос увидит stale=1 и выполнится заново
SELECT count() FROM orders SETTINGS use_query_cache = 1;
Для ручной очистки всего кеша:
SYSTEM DROP QUERY CACHE;
Когда использовать Query Result Cache
Подходит для:
- Дашборды с высокой read-нагрузкой и одинаковыми запросами
- Повторяющиеся аналитические отчёты (ежечасные, ежедневные)
- Read-heavy workloads с редкими обновлениями данных
Не подходит для:
- Сценарии с требованием data freshness (real-time мониторинг)
- Таблицы с высокочастотными INSERT (кеш будет постоянно инвалидироваться)
- Запросы с non-deterministic функциями (now(), rand())
Ключевые выводы
SETTINGS use_query_cache = 1включает server-side кеширование для конкретного запроса или сессии. Повторный идентичный запрос возвращается без чтения данных.- Non-deterministic функции (now(), rand(), currentUser()) блокируют кеширование — QueryCacheMisses будет расти при каждом выполнении.
SELECT event, value FROM system.events WHERE event LIKE 'QueryCache%'показывает hits/misses — основная метрика эффективности кеша.- Кеш автоматически инвалидируется при INSERT в исходную таблицу.
SYSTEM DROP QUERY CACHE— ручная очистка. query_cache_min_query_durationпозволяет кешировать только тяжёлые запросы, избегая overhead для быстрых.