SELECT-запросы только один раз, а при последующих выполнениях того же запроса отдавать результаты напрямую из кэша.
В зависимости от типа запросов это может значительно снизить задержку и расход ресурсов ClickHouse server.
Предпосылки, устройство и ограничения
- В транзакционно согласованных кэшах база данных инвалидирует (отбрасывает) кэшированные результаты запросов, если результат запроса
SELECTизменяется или потенциально может измениться. В ClickHouse к операциям, изменяющим данные, относятся вставки/обновления/удаления в таблицах или из таблиц, а также схлопывающие слияния. Транзакционно согласованное кэширование особенно хорошо подходит для OLTP-баз данных, например MySQL (где кэш запросов был удалён после v8.0) и Oracle. - В транзакционно несогласованных кэшах допускаются небольшие неточности в результатах запросов при условии, что всем записям кэша
назначается срок действия, по истечении которого они устаревают (например, 1 минута), и что базовые данные в течение этого периода изменяются лишь незначительно.
Такой подход в целом лучше подходит для OLAP-баз данных. В качестве примера, где транзакционно несогласованного кэширования достаточно,
рассмотрим почасовой отчёт по продажам в инструменте отчётности, который одновременно просматривают несколько пользователей. Данные о продажах обычно изменяются
достаточно медленно, поэтому базе данных нужно вычислить отчёт только один раз (это соответствует первому запросу
SELECT). Последующие запросы могут обслуживаться напрямую из кэша запросов. В этом примере разумный срок действия может составлять 30 мин.
Настройки конфигурации и использование
В ClickHouse Cloud для изменения настроек кэша запросов необходимо использовать настройки на уровне запроса. Изменение настроек на уровне конфигурации в настоящее время не поддерживается.
clickhouse-local выполняет только один запрос за раз. Поскольку кэширование результатов запросов в этом случае не имеет смысла, кэш
результатов запросов в clickhouse-local отключён.
use_query_cache = true) будет
считываться вычисленный результат из кэша и немедленно возвращаться.
Параметр
use_query_cache и все остальные настройки, связанные с кэшем запросов, действуют только для отдельных операторов SELECT. В частности,
результаты SELECT к представлениям, созданным с помощью CREATE VIEW AS SELECT [...] SETTINGS use_query_cache = true, не кэшируются, если только сам оператор SELECT
не выполняется с SETTINGS use_query_cache = true.true). Первый параметр
управляет тем, сохраняются ли результаты запросов в кэше, а второй определяет, должна ли база данных пытаться получать результаты запросов
из кэша. Например, следующий запрос будет использовать кэш только пассивно, то есть пытаться читать из него, но не сохранять в нём свой
результат:
use_query_cache, enable_writes_to_query_cache и
enable_reads_from_query_cache только для конкретных запросов. Также можно включить кэширование на уровне пользователя или профиля (например, через SET use_query_cache = true), однако следует помнить, что тогда все запросы SELECT могут возвращать кэшированные результаты.
Кэш запросов можно очистить с помощью оператора SYSTEM CLEAR QUERY CACHE. Содержимое кэша запросов отображается в системной таблице
system.query_cache. Число попаданий и промахов кэша запросов с момента запуска базы данных показано как события
“QueryCacheHits” и “QueryCacheMisses” в системной таблице system.events. Оба счётчика обновляются только для
запросов SELECT, выполняемых с настройкой use_query_cache = true; другие запросы не влияют на “QueryCacheMisses”. Поле query_cache_usage
в системной таблице system.query_log показывает для каждого выполненного запроса, был ли результат запроса записан в
кэш запросов или прочитан из него. Метрики QueryCacheEntries и QueryCacheBytes в системной таблице
system.metrics показывают, сколько записей / байт сейчас содержит кэш запросов.
Кэш запросов существует в единственном экземпляре для каждого процесса сервера ClickHouse. Однако кэшированные результаты по умолчанию не являются
общими для разных пользователей. Это можно изменить (см. ниже), но по соображениям безопасности делать этого не рекомендуется.
Результаты запросов в кэше запросов определяются по абстрактному синтаксическому дереву (AST)
самого запроса. Это означает, что кэширование не чувствительно к регистру, например SELECT 1 и select 1 считаются одним и тем же запросом. Чтобы
сопоставление было более естественным, из AST удаляются все настройки уровня запроса, связанные с кэшем запросов и форматированием вывода).
Если запрос был прерван из-за исключения или отменён пользователем, в кэш запросов никакая запись не добавляется.
Размер кэша запросов в байтах, максимальное число записей кэша и максимальный размер отдельных записей кэша (в байтах и в
записях) можно настроить с помощью различных параметров конфигурации сервера.
users.xml, затем сделайте оба параметра
доступными только для чтения:
Age и Expires, указывая возраст (в секундах) и временную метку истечения
кэшированной записи.
Записи в кэше запросов по умолчанию сжимаются. Это уменьшает общее потребление памяти ценой более медленной записи в кэш запросов / чтения
из кэша запросов. Чтобы отключить сжатие, используйте настройку query_cache_compress_entries.
Иногда бывает полезно хранить в кэше несколько результатов для одного и того же запроса. Этого можно добиться с помощью настройки
query_cache_tag, которая выступает как метка (или пространство имен) для записей кэша запросов. Кэш запросов
считает результаты одного и того же запроса с разными тегами разными.
Пример создания трех разных записей кэша запросов для одного и того же запроса:
tag, можно использовать оператор SYSTEM CLEAR QUERY CACHE TAG 'tag'.
ClickHouse читает данные таблицы блоками по max_block_size строк. Из-за фильтрации, агрегации
и т. п. результирующие блоки обычно значительно меньше, чем max_block_size, хотя в некоторых случаях они могут быть и гораздо больше. Настройка
query_cache_squash_partial_results (включена по умолчанию) определяет, будут ли результирующие блоки
объединяться (если они слишком малы) или разделяться (если они большие) на блоки размером max_block_size перед записью в кэш результатов
запросов. Это снижает производительность записи в кэш запросов, но повышает степень сжатия записей кэша и обеспечивает более естественную
гранулярность блоков, когда результаты запросов впоследствии отдаются из кэша запросов.
В результате кэш запросов хранит для каждого запроса несколько (частичных)
результирующих блоков. Хотя такое поведение по умолчанию вполне оправданно, его можно отключить с помощью настройки
query_cache_squash_partial_results.
Кроме того, результаты запросов с недетерминированными функциями по умолчанию не кэшируются. К таким функциям относятся
- функции доступа к словарям:
dictGet()и т. д. - пользовательские функции без тега
<deterministic>true</deterministic>в их XML- определении, - функции, возвращающие текущую дату или время:
now(),today(),yesterday()и т. д., - функции, возвращающие случайные значения:
randomString(),fuzzBits()и т. д., - функции, результат которых зависит от размера, порядка или внутренних фрагментов, используемых при обработке запросов:
nowInBlock()и т. д.,rowNumberInBlock(),runningDifference(),blockSize()и т. д., - функции, зависящие от окружения:
currentUser(),queryID(),getMacro()и т. д.