Перейти к содержимому
Последнее обновление

SQL Cache: руководство по кэшированию запросов

SQL Cache — это механизм кэширования результатов запросов в Doris. Он сохраняет результаты запросов, используя в качестве ключа метаданные, такие как текст SQL и версия данных, чтобы при последующих идентичных запросах возвращать результаты непосредственно из кэша. Это существенно сокращает затраты на повторные вычисления.

Контрольный список перед чтением​

Прежде чем читать это руководство, убедитесь, что вы разобрались в следующих вопросах и выполнили необходимые приготовления:

  • Подходит ли кэширование для вашего сценария запросов (например, для офлайн-аналитики T+1 или данных, которые редко обновляются)
  • Поддерживает ли ваша текущая версия Doris просмотр SQL Cache через explain plan (рекомендуется 2.1.3+)
  • Понимаете ли вы, что SQL Cache поддерживает только внутренние таблицы OlapTable и внешние таблицы Hive
  • Понимаете ли вы, что недетерминированные функции (например, now() и random()) влияют на долю попаданий в кэш
  • Есть ли у вас права на изменение конфигурации FE/BE (для управления памятью и глобального включения кэша)

Прежде чем включать SQL Cache, проверьте по каждому пункту, что ваши запросы соответствуют следующим условиям:

  • Операторы SQL выполняются многократно с высокой частотой
  • Данные обновляются редко (что обеспечивает высокую долю попаданий в кэш)
  • Запросы не содержат функций со случайным результатом (например, random())
  • Набор полей метрик остаётся одинаковым во всех запросах (без динамического добавления или удаления)

1. Введение в концепцию​

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

Ключевые факторы попадания в кэш​

SQL Cache однозначно идентифицирует кэшированные данные по сочетанию следующих факторов:

Ключевой факторОписание
Текст SQLПолностью идентичная строка SQL
Определение представленияDDL-определение всех используемых представлений
Версии таблиц и партицийИзменялись ли данные
Пользовательские переменные и их значенияТекущие значения переменных, используемых в SQL
Недетерминированные функции и их результатыВычисленные результаты функций, таких как now() и random()
Определение политики строкКонфигурация Row Policy
Определение маскирования данныхКонфигурация Data Masking

При изменении любого фактора (например, при переписывании SQL, изменении полей или условий запроса либо изменении версии из-за обновления данных) попадания в кэш не будет. Для запросов с Join нескольких таблиц обновление любой из таблиц меняет идентификатор или номер версии партиции, что делает попадание в кэш невозможным.

Подходящие сценарии​

  • Настоятельно рекомендуется: сценарии обновления T+1. Данные обновляются ночью; первый запрос получает результат от BE и записывает его в кэш, а последующие идентичные запросы возвращают результат непосредственно из кэша.
  • Возможно использование: данные, обновляемые в реальном времени. SQL Cache можно включить и в этом случае, но доля попаданий будет низкой.
  • Поддерживаемые типы таблиц: в настоящее время поддерживаются внутренние таблицы OlapTable и внешние таблицы Hive.

2. Ограничения​

Влияние недетерминированных функций​

Определение: недетерминированная функция — это функция, результат которой не имеет фиксированной зависимости от входных параметров.

ФункцияПоведениеВозможность использования кэша
now()Возвращает текущее время с точностью до секунды, меняется каждую секундуПовторное использование возможно в пределах одной секунды
date(now())Преобразует время с точностью до секунды в дату с точностью до дняПовторное использование возможно в пределах одного дня (рекомендуется)
random()Возвращает разный результат при каждом вызовеПрактически никогда не даёт попаданий в кэш

Совет по оптимизации: уменьшайте точность представления времени. Например, используйте select * from tbl where dt = date(now()) вместо select * from tbl where dt = now(), чтобы все запросы в пределах одного дня могли попадать в кэш. Избегайте использования в запросах функций с высокой степенью недетерминированности, таких как random().

Влияние добавления полей метрик​

SQL Cache кэширует результаты строго по запрашиваемым полям. Он не поддерживает выполнение запроса с большим количеством метрик за счёт кэша с меньшим количеством метрик.

СценарийПоведениеПоследствия
Результат для 2 метрик уже закэширован, а новый запрос запрашивает 3 метрикиПовторно использовать кэш невозможно, запрос необходимо выполнить зановоДоля попаданий снижается, а новый результат записывается в новую запись кэша

Совет по оптимизации: сохраняйте стабильный набор полей метрик в бизнес-отчётах и шаблонах запросов. Если нужно добавить метрики, измените шаблон запроса, а не расширяйте его от случая к случаю, чтобы кэш оставался пригодным для использования.

3. Принципы реализации​

Реализация на FE​

Последовательность обработки после получения запроса FE:

  1. Поиск метаданных: поиск метаданных в памяти по строке SQL в качестве ключа (метаданные содержат версии таблиц и партиций).
  2. Сравнение версий: если метаданные не изменились, данные также не менялись и кэш можно использовать повторно.
  3. Пропуск разбора: пропуск разбора и оптимизации SQL и определение соответствующего BE с помощью консистентного хеширования.
  4. Возврат результата:
    • Попадание в кэш на BE: результат возвращается непосредственно клиенту.
    • Промах кэша: выполняется полный цикл разбора SQL, оптимизации и вычислений.
  5. Запись результата в кэш: после завершения вычислений на BE процесс FE сохраняет результат на соответствующем BE и записывает метаданные в собственную память для повторного использования при следующем запросе.

Специальная оптимизация: если на этапе оптимизации SQL установлено, что число строк в результате равно только 0 или 1, FE сохраняет результат непосредственно в собственной памяти, чтобы ускорить последующие идентичные запросы.

Реализация на BE​

  • Для хранения результата выбирается BE с помощью консистентного хеширования. Результат хранится в памяти BE в структуре HashMap.
  • При чтении из кэша или записи в него в качестве ключа используется дайджест метаданных, таких как строка SQL, что позволяет быстро получать данные результата.

4. Быстрый старт​

Шаг 1: Включение и отключение SQL Cache​

Цель: включить SQL Cache на уровне сеанса или глобально (по умолчанию отключён).

-- Turn on SQL Cache in the current session; it is off by default
set enable_sql_cache=true;
-- Turn off SQL Cache in the current session
set enable_sql_cache=false;

-- Turn on SQL Cache globally; it is off by default
set global enable_sql_cache=true;
-- Turn off SQL Cache globally
set global enable_sql_cache=false;

Примечания: настройка на уровне сеанса действует только в текущем сеансе. Глобальная настройка действует для всех вновь создаваемых сеансов.

Шаг 2: Проверка попадания запроса в SQL Cache​

Способ A: Использование explain plan (для Doris 2.1.3+)​

Цель: определить по плану запроса, произошло ли попадание в кэш. Команда: выполните explain plan <your SQL>. Примечания: если в дереве плана запроса появляется узел LogicalSqlCache или PhysicalSqlCache, запрос попал в SQL Cache.

> explain plan select * from t2;

+------------------------------------------------------------------------------------------------------------+
| Explain String(Nereids Planner) |
+------------------------------------------------------------------------------------------------------------+
| ========== PARSED PLAN (time: 28ms) ========== |
| LogicalSqlCache[1] ( queryId=711dea740e4746e6-8bc11afe08f6542c ) |
| +--PhysicalResultSink[39] ( outputExprs=[id#0, name#1] ) |
| +--PhysicalOlapScan[t2]@0 ( stats=12 ) |
| |
| ========== ANALYZED PLAN ========== |
| LogicalSqlCache[1] ( queryId=711dea740e4746e6-8bc11afe08f6542c ) |
| +--PhysicalResultSink[39] ( outputExprs=[id#0, name#1] ) |
| +--PhysicalOlapScan[t2]@0 ( stats=12 ) |
| |
| ========== REWRITTEN PLAN ========== |
| LogicalSqlCache[1] ( queryId=711dea740e4746e6-8bc11afe08f6542c ) |
| +--PhysicalResultSink[39] ( outputExprs=[id#0, name#1] ) |
| +--PhysicalOlapScan[t2]@0 ( stats=12 ) |
| |
| ========== OPTIMIZED PLAN ========== |
| PhysicalSqlCache[3] ( queryId=711dea740e4746e6-8bc11afe08f6542c, backend=192.168.126.3:9051, rowCount=12 ) |
| +--PhysicalResultSink[39] ( outputExprs=[id#0, name#1] ) |
| +--PhysicalOlapScan[t2]@0 ( stats=12 ) |
+------------------------------------------------------------------------------------------------------------+

Способ B: Просмотр Profile (для версий до Doris 2.1.3)​

Цель: подтвердить попадание в кэш в версиях, которые не поддерживают explain plan. Команда: включите Profile и просмотрите сводку выполнения. Примечания: если поле Is Cached: содержит Yes, запрос попал в SQL Cache.

Execution  Summary:
- Parse SQL Time: 18ms
- Nereids Analysis Time: N/A
- Nereids Rewrite Time: N/A
- Nereids Optimize Time: N/A
- Nereids Translate Time: N/A
- Workload Group: normal
- Analysis Time: N/A
- Wait and Fetch Result Time: N/A
- Fetch Result Time: 0ms
- Write Result Time: 0ms
- Doris Version: 915138e801
- Is Nereids: Yes
- Is Cached: Yes
- Total Instances Num: 0
- Instances Num Per BE:
- Parallel Fragment Exec Instance Num: 1
- Trace ID:
- Transaction Commit Time: N/A
- Nereids Distribute Time: N/A

5. Мониторинг метрик​

Метрики мониторинга FE​

Адрес: http://${FE_IP}:${FE_HTTP_PORT}/metrics Примечания: значения счётчиков монотонно возрастают. После перезапуска FE отсчёт снова начинается с 0.

# 1 SQL has been written to the cache
doris_fe_cache_added{type="sql"} 1

# The SQL Cache has been hit 2 times
doris_fe_cache_hit{type="sql"} 2

Метрики мониторинга BE​

Адрес: http://${BE_IP}:${BE_HTTP_PORT}/metrics Примечания: разные записи кэша могут храниться на разных BE. Чтобы получить полную картину, необходимо собирать метрики со всех BE.

# There are currently 1205 caches in the memory of this BE
doris_be_query_cache_sql_total_count 1205

# All caches currently take up about 44KB of BE memory
doris_be_query_cache_memory_total_byte 44101

6. Управление памятью​

Управление памятью FE​

Метаданные кэша в FE используют слабые ссылки: при нехватке памяти на FE автоматически освобождаются метаданные, к которым дольше всего не обращались. Для ограничения использования памяти также поддерживаются следующие параметры:

ПараметрЗначение по умолчаниюОписание
sql_cache_manage_num100Максимальное количество записей метаданных; при превышении автоматически освобождается запись, к которой дольше всего не обращались
expire_sql_cache_in_fe_second300Срок действия метаданных (в секундах); они автоматически освобождаются, если к ним не обращались в течение этого времени
cache_result_max_row_count3000Максимальное количество строк результата; при превышении SQL Cache не создаётся
cache_result_max_data_size31457280 (30MB)Максимальный размер результата (в байтах); при превышении SQL Cache не создаётся

Команды настройки (вступают в силу немедленно; их нужно выполнить на каждом FE; для сохранения настроек запишите их в fe.conf):

-- Store at most 100 cache metadata entries
ADMIN SET FRONTEND CONFIG ('sql_cache_manage_num'='100');

-- Automatically release a cache metadata entry that has not been accessed for 300 seconds
ADMIN SET FRONTEND CONFIG ('expire_sql_cache_in_fe_second'='300');

-- Do not create SQL Cache when the result has more than 3000 rows by default
ADMIN SET FRONTEND CONFIG ('cache_result_max_row_count'='3000');

-- Do not create SQL Cache when the result is larger than 30MB by default
ADMIN SET FRONTEND CONFIG ('cache_result_max_data_size'='31457280');

Управление памятью BE​

ПараметрЗначение по умолчанию (пример)Описание
query_cache_max_size_mb256Верхний предел объёма памяти, используемой кэшем в штатном режиме
query_cache_elasticity_size_mb128Резерв для временного расширения; при превышении суммы max + elasticity начинается вытеснение записей, которое продолжается, пока использование памяти не опустится ниже max

Файл конфигурации: be.conf (после изменения необходимо перезапустить BE).

-- When the cache memory usage exceeds query_cache_max_size_mb + query_cache_elasticity_size_mb,
-- release the least recently used cache entries until the memory usage drops below query_cache_max_size_mb.
query_cache_max_size_mb = 256
query_cache_elasticity_size_mb = 128

7. Устранение неполадок: исследование инвалидации кэша​

В следующей таблице перечислены распространённые причины промахов кэша или его инвалидации и соответствующие направления проверки:

№Причина инвалидацииТипичная операцияРекомендация по проверке
1Изменение структуры таблицы или представленияdrop table, replace table, alter table, alter viewПроверьте историю недавних DDL-операций с таблицами и представлениями
2Изменение данных таблицыinsert, delete, update, truncateПроверьте журналы загрузки и изменений, чтобы определить, изменилась ли версия данных
3Отзыв прав пользователяrevokeПроверьте изменения прав учётной записи, выполняющей запрос
4Использование недетерминированных функцийselect random(), select now(), и т. д.Перейдите на функции с меньшей точностью или постоянные параметры
5Изменение значения переменнойselect * from tbl where dt = @dt_varПроверьте, совпадают ли значения переменных сеанса
6Изменение Row Policy / Data MaskingИзменена политика строк или маскированияПроверьте историю недавних изменений политики
7Количество строк результата превышает ограничениеПревышено значение cache_result_max_row_count (по умолчанию 3000 строк)Измените порог или сократите набор результатов
8Размер результата превышает ограничениеПревышено значение cache_result_max_data_size (по умолчанию 30 МБ)Измените порог или сократите набор возвращаемых полей

8. Часто задаваемые вопросы​

В1: Включён ли SQL Cache по умолчанию? О: По умолчанию он отключён. Включите его на уровне сеанса с помощью set enable_sql_cache=true или глобально с помощью set global enable_sql_cache=true.

В2: Какие типы таблиц поддерживает SQL Cache? О: В настоящее время поддерживаются внутренние таблицы OlapTable и внешние таблицы Hive.

В3: Можно ли использовать SQL Cache для данных, обновляемых в реальном времени? О: Да, но каждое обновление данных меняет версию партиции, что приводит к инвалидации кэша. Доля попаданий будет низкой. SQL Cache лучше подходит для сценариев офлайн-аналитики T+1.

В4: Как происходит инвалидация кэша для запросов с Join нескольких таблиц? О: Как только данные меняются в любой из таблиц, участвующих в Join, изменяется идентификатор или номер версии партиции, и попадание в кэш всего запроса становится невозможным.

В: Ранее были закэшированы две метрики. Можно ли повторно использовать кэш для запроса, который теперь запрашивает три метрики? О: Нет. SQL Cache кэширует результаты строго по запрашиваемым полям. Кэш с меньшим количеством метрик не может удовлетворить запрос с большим количеством метрик, поэтому запрос необходимо выполнить заново.

В5: Приводит ли функция now() к полной инвалидации кэша? О: Нет, полной инвалидации не происходит. Функция now() возвращает время с точностью до секунды, поэтому идентичные запросы в пределах одной секунды могут повторно использовать кэш. Чтобы увеличить период, в течение которого возможны попадания в кэш, используйте date(now()) для преобразования времени в дату с точностью до дня.

В6: Где хранятся кэшированные данные? О: Подавляющее большинство результатов хранится в памяти BE (в структуре HashMap). Если число строк в результате равно только 0 или 1, FE сохраняет его непосредственно в собственной памяти.

В7: Доступен ли кэш после перезапуска FE? О: Метаданные в FE теряются, а метрики мониторинга также сбрасываются до 0. Результаты в памяти BE тоже становятся недействительными после перезапуска.

9. Сравнение и дополнительные сведения​

КритерийSQL CachePartition Cache (где применимо)
Уровень кэшированияНабор результатов всего запроса SQLКэширование промежуточных результатов по партициям
Подходящий характер обновленийT+1, редкие обновленияНекоторые партиции обновляются часто, а остальные остаются неизменными
Условие попаданияТекст SQL и все зависимые метаданные не изменилисьВерсии задействованных партиций не изменились
Уровень инвалидацииИзменение любой зависимости приводит к инвалидации всего кэшаПовторно вычисляются только партиции, для которых не было попадания в кэш

Примечание: столбец Partition Cache в этой таблице приведён только для сравнения. Фактическая доступность зависит от возможностей текущей версии Doris.