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

Condition Cache

Кратко Apache Doris Condition Cache сохраняет результат вычисления условия WHERE для каждого сегмента в виде сжатого битового вектора с ключом (predicate digest, key range). Следующий запрос, применяющий тот же фильтр к тому же сегменту, пропускает гранулы, для которых битовый вектор уже указывает на отсутствие совпадений, даже если список SELECT, GROUP BY или агрегация отличаются. Пять панелей дашборда с общим условием WHERE region = 'ASIA' AND order_date >= '2023-01-01' вычисляют этот фильтр один раз для каждого сегмента и повторно используют результат во всех панелях.

Apache Doris Condition Cache: кеш на уровне сегментов, который хранит результаты вычисления фильтров в виде битовых векторов, позволяя запросам с одинаковым условием WHERE повторно использовать результаты проверки предикатов.

Зачем использовать Apache Doris Condition Cache?​

Apache Doris Condition Cache повторно использует результаты вычисления предикатов в запросах с одинаковым условием WHERE, которые во всём остальном могут различаться, заполняя пробел между SQL Cache и Query Cache. В большинстве аналитических нагрузок объём работы по фильтрации гораздо больше, чем по агрегации. Дашборд на основе одной таблицы orders может содержать десять панелей, у которых общее условие WHERE region = ? AND order_date >= ?, а различается только список SELECT. Бэкенд приложения каждые несколько секунд повторяет тот же предикат с новой агрегацией. Отчёт T+1 выполняет разные агрегации по партициям, которые не менялись с прошлой ночи.

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

SQL Cache помогает, когда текст SQL совпадает побайтно, и перестаёт работать при малейшем изменении списка SELECT. Query Cache помогает запросам агрегации, которые используют одни и те же tablet целиком. Ни один из них не помогает, когда условие WHERE общее, а список SELECT различается.

Apache Doris Condition Cache занимает место между ними: он кеширует этап вычисления предиката на уровне сегмента независимо от того, что остальная часть запроса делает со строками.

Что такое Apache Doris Condition Cache?​

Apache Doris Condition Cache представляет собой кеш результатов вычисления предикатов на стороне BE. Для каждого сегмента результаты хранятся в виде битового вектора с детализацией до гранулы. При запуске сканирования сегмента BE вычисляет 64-битный дайджест на основе выражения предиката и диапазона ключей сегмента, затем проверяет кеш. При попадании он пропускает все гранулы с битом 0 и сканирует только гранулы с битом 1. При промахе он вычисляет предикат обычным образом и записывает полученный битовый вектор в кеш.

Кеш не зависит от проекций, агрегаций, соединений и сортировки. Два запроса с одинаковыми условиями WHERE используют общие записи кеша, даже если один выполняет SELECT *, а другой выполняет SELECT COUNT(DISTINCT customer_id).

Основные термины

  • enable_condition_cache: переменная сеанса. Включена по умолчанию; задайте false, чтобы отключить кеш для одного запроса или одного сеанса.
  • Сегмент: файл внутри tablet, запись в который уже завершена. После записи сегмент больше не изменяется; вместо этого compaction создаёт новые сегменты. Эта неизменяемость и делает использование кеша безопасным.
  • Гранула: блок из 2048 строк внутри сегмента. Битовые векторы хранят один бит на гранулу, а не на строку.
  • Дайджест предиката: 64-битный хеш конъюнктивного предиката вместе с диапазоном ключей сегмента. Семантически эквивалентные предикаты дают одинаковый дайджест.
  • condition_cache_limit: ограничение объёма памяти для кеша на каждом BE, в MB. Значение по умолчанию: 1024. Задаётся в be.conf.

Как работает Apache Doris Condition Cache?​

Apache Doris Condition Cache хеширует каждый конъюнктивный предикат вместе с диапазоном ключей сегмента в 64-битный дайджест, ищет его в локальном LRU-кеше BE и пропускает все гранулы, для которых сохранён бит 0.

  1. Вычисление дайджеста (BE). Когда оператор сканирования начинает работу с сегментом, он нормализует свои конъюнктивные предикаты и диапазон ключей сегмента, формируя 64-битный дайджест. Разные списки SELECT, условия GROUP BY и агрегации дают одинаковый дайджест, поскольку не влияют на предикат.
  2. Проверка для каждого сегмента. BE ищет (digest, segment_id) в шардированном LRU-кеше. Если у сегмента есть маркер удаления или предикат сформирован runtime-фильтром TopN во время выполнения, BE пропускает поиск в кеше и выполняет обычное сканирование.
  3. При попадании. Оператор сканирования читает битовый вектор, пропускает все гранулы с битом 0 и декодирует столбцы только для гранул с битом 1. Фильтрация на уровне строк в этих гранулах подтверждает совпадения.
  4. При промахе. Оператор сканирования вычисляет предикат обычным образом, по ходу работы строит битовый вектор и записывает результат в кеш с ключом (digest, segment_id). Последующие запросы с тем же дайджестом получают попадание в кеш.
  5. Инвалидация благодаря неизменяемости. Сегменты не изменяются. Новая операция INSERT или compaction создаёт новый сегмент с новым ID, а старая запись кеша со временем самостоятельно вытесняется из LRU. Apache Doris не требуется отдельный этап инвалидации.

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

SET enable_condition_cache = true;

-- Run 1: misses every segment, builds bit vectors, writes them back
SELECT region, country, SUM(amount)
FROM orders
WHERE region = 'ASIA' AND order_date >= '2023-01-01'
GROUP BY region, country;

-- Run 2: different SELECT, same WHERE; hits the cache on every segment
SELECT COUNT(DISTINCT customer_id)
FROM orders
WHERE region = 'ASIA' AND order_date >= '2023-01-01';

Ожидаемый результат (фрагмент EXPLAIN PROFILE для запуска 2)

ConditionCacheSegmentHit:    42
ConditionCacheFilteredRows: 18,400,219

Первый запуск сканирует каждый сегмент, вычисляет предикат и записывает по одному битовому вектору на сегмент. Второй запуск использует то же условие WHERE, поэтому дайджест совпадает; для каждого сегмента происходит попадание в кеш, и BE пропускает гранулы, для которых уже известно, что они не содержат строк, соответствующих условию region = 'ASIA' AND order_date >= '2023-01-01'.

Когда стоит использовать Apache Doris Condition Cache?​

Включайте Apache Doris Condition Cache для нагрузок с преобладанием чтения, где многие запросы повторно используют одно и то же условие WHERE, а таблица не испытывает постоянной высокой нагрузки на запись.

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

  • Дашборды, где многие панели используют общее условие WHERE и различаются только списком SELECT или агрегацией.
  • Трафик приложений, которые часто повторяют один и тот же предикат для таблиц с редкими операциями записи.
  • Отчёты T+1, выполняющие разные агрегации по уже загруженным партициям за вчерашний день.
  • Высокоселективные фильтры, при которых большинство гранул получают бит 0, а кеш позволяет пропускать большие части каждого сегмента при сканировании.

Неподходящие сценарии

  • Таблицы с постоянной высокой нагрузкой на запись. Новые сегменты означают новые дайджесты, а старые записи кеша вытесняются из LRU раньше, чем используются повторно. Если нужно повторно использовать результаты агрегаций при неизменной структуре запроса, используйте Query Cache.
  • Запросы, обращающиеся к сегментам с маркерами удаления. BE обходит кеш, чтобы сохранить корректную семантику удаления, поэтому при частых операциях DELETE кеш срабатывает редко.
  • Запросы, предикат которых формируется runtime-фильтром TopN во время выполнения. Пока не поддерживаются.
  • Низкоселективные фильтры, которым соответствует большинство строк. Затраты на сканирование подходящих гранул сохраняются; кеш экономит работу только на гранулах, для которых уже известно об отсутствии совпадений.
  • Ситуативные запросы с разовыми условиями WHERE, которые не используются повторно в других запросах. Кеш заполняется записями, которые читаются по одному разу, а затем вытесняют друг друга. Можно оставить его включённым, но доля попаданий, скорее всего, будет низкой.
  • Поиск по первичному ключу. Вместо этого используйте точечные запросы при высокой конкурентной нагрузке.

Дополнительные материалы​