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

Отсечение данных

Кратко Благодаря отсечению данных в Apache Doris запрос фактически сканирует лишь ту часть таблицы, которая осталась после последовательного применения нескольких уровней отсечения. Ключи партиционирования и распределения, статистика min/max в ZoneMap, индексы BloomFilter и NGram BloomFilter на каждом уровне исключают очередную часть данных, которую движку не придётся читать. Большая часть выигрыша достигается автоматически; администратор управляет отсечением через выбор параметров DDL и проверяет результат в выводе EXPLAIN.

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

Зачем использовать отсечение данных в Apache Doris?​

Отсечение данных в Apache Doris позволяет запросу пропустить большую часть таблицы ещё до её чтения, сокращая сканирование многих терабайт до чтения нескольких партиций или таблетов. Самый быстрый способ ускорить OLAP-запрос: читать меньше данных. Широкая таблица событий, пополняемая на 50 GB в день, за год разрастается до петабайт, а большинству запросов нужна лишь малая часть: один день, один пользователь, один продукт. Без отсечения планировщик распределяет запрос по всем партициям и всем таблетам, а исполнитель читает с диска каждую страницу, чтобы проверить условие WHERE.

Это приводит к трём конкретным проблемам:

  • Запрос с условием WHERE date BETWEEN '2026-04-01' AND '2026-04-07' к таблице с 365 партициями обращается ко всем партициям, пока планировщик не получит информацию о том, какие из них можно пропустить.
  • Точечные запросы к таблицам с хеш-распределением (WHERE user_id = 12345) превращаются в полное сканирование таблетов, если оптимизатор не может связать предикат с ключом бакетирования.
  • Фильтры по столбцам с большим числом уникальных значений, не входящим в ключ (WHERE phone = '...'), читают каждый сегмент, поскольку нет статистики, позволяющей исключить страницы.

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

Что такое отсечение данных в Apache Doris?​

Отсечение данных в Apache Doris представляет собой совокупный результат всех этапов чтения, на которых движок может пропустить данные, не читая их: от партиций и таблетов до сегментов и страниц столбцов. Планировщик Frontend выполняет отсечение на крупном уровне, используя метаданные таблицы: партиции и таблеты. Backend выполняет более детальное отсечение во время сканирования: ZoneMap min/max, BloomFilter, NGram BloomFilter и инвертированный индекс определяют, можно ли пропустить сегмент, страницу столбца или даже диапазон строк.

Ключевые термины

  • Partition pruning: планировщик использует предикаты диапазона или списка значений по ключу партиционирования, чтобы исключить ненужные партиции ещё до назначения таблетов на выполнение.
  • Bucket (tablet) pruning: предикаты равенства по ключу DISTRIBUTED BY HASH позволяют планировщику выбрать только те бакеты, которые могут содержать искомую строку.
  • ZoneMap index: статистика min/max/null для каждого сегмента и каждой страницы, автоматически создаваемая для всех столбцов. Предикаты диапазона используют её для пропуска страниц.
  • BloomFilter index: явно включаемый вероятностный фильтр для отдельного столбца, полезный для предикатов равенства и IN по столбцам с большим числом уникальных значений.
  • NGram BloomFilter: явно включаемый индекс, который превращает предикаты поиска подстроки LIKE '%abc%' в проверки n-грамм по BloomFilter.
  • Runtime filter: фильтр, создаваемый во время соединения на основе данных одной его стороны и проталкиваемый на другую сторону для отсечения данных.

Как работает отсечение данных в Apache Doris?​

Отсечение данных в Apache Doris работает на пяти последовательных уровнях: партиции, таблеты, сегменты/страницы, проверки индексов и фильтры времени выполнения. Каждый уровень сокращает объём входных данных для следующего.

  1. Отсечение партиций (FE). Планировщик Nereids запускает PruneOlapScanPartition, сопоставляет предикаты WHERE с деревом партиций таблицы, заданных диапазонами или списками значений, и формирует набор оставшихся партиций. EXPLAIN показывает его как partitions=2/4 (p2,p3).
  2. Отсечение таблетов (FE). PruneOlapScanTablet извлекает предикаты равенства по столбцу бакетирования и с помощью HashDistributionPruner определяет, в какие бакеты хешируются эти значения. EXPLAIN показывает tablets=1/32.
  3. Отсечение сегментов / страниц (BE). Для каждой оставшейся таблеты итератор сегментов открывает средства чтения столбцов и обращается к индексу ZoneMap. Если [min, max] не пересекается с диапазоном предиката, страница исключается без распаковки.
  4. Проверки индексов (BE). BloomFilter, NGram BloomFilter и инвертированные индексы проверяются до декодирования строк. Отсутствие совпадения позволяет пропустить страницу; наличие совпадения означает лишь, что на странице могут быть подходящие строки.
  5. Фильтры времени выполнения (FE/BE). При соединении фильтры формируются на стороне построения (например, IN (A.id_set)) и рассылаются так, чтобы сканирование на стороне проверки могло использовать те же механизмы отсечения во время выполнения.

К моменту проверки предикатов большая часть таблицы уже исключена без чтения.

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

CREATE TABLE events (
ts DATETIME, user_id BIGINT, action VARCHAR(64)
)
DUPLICATE KEY(ts, user_id)
PARTITION BY RANGE(ts) (
PARTITION p202604 VALUES LESS THAN ("2026-05-01"),
PARTITION p202605 VALUES LESS THAN ("2026-06-01")
)
DISTRIBUTED BY HASH(user_id) BUCKETS 16
PROPERTIES ("bloom_filter_columns" = "action");

EXPLAIN
SELECT count(*) FROM events
WHERE ts >= '2026-05-08' AND user_id = 42 AND action = 'click';

Ожидаемый результат (фрагмент)

0:VOlapScanNode
TABLE: events
PREDICATES: ts >= '2026-05-08', user_id = 42, action = 'click'
partitions=1/2 (p202605)
tablets=1/16

Планировщик оставил одну партицию из двух (по диапазону дат) и одну таблету из шестнадцати (по хешу user_id). Во время чтения BE использует ZoneMap для ts и BloomFilter для action, чтобы пропускать страницы внутри оставшейся таблеты. Четыре уровня отсечения обрабатывают три предиката без ручной настройки.

Когда стоит использовать отсечение данных в Apache Doris?​

Отсечение данных в Apache Doris работает всегда; вопрос лишь в том, какие уровни задействуют ваши определения DDL и предикаты. Больше всего выигрывают аналитические запросы с ограничением по времени, точечные запросы при высокой конкурентной нагрузке, поиск подстрок в длинных текстовых столбцах и соединения по схеме «звезда». Типичные ошибки: неуместное применение BloomFilter и партиции, в которые попадают все данные.

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

  • Аналитические запросы с ограничением по времени к партиционированным таблицам. Кривая задержки выравнивается, как только предикат даты становится доступен планировщику.
  • Точечные запросы при высокой конкурентной нагрузке к таблицам с хеш-распределением. Выбирайте ключ бакетирования в соответствии с наиболее частым предикатом равенства.
  • Поиск подстрок в длинных текстовых столбцах. Добавьте NGram BloomFilter, чтобы LIKE '%...%' выполнялся через проверку BloomFilter вместо сканирования столбца.
  • Соединения по схеме «звезда». Фильтры времени выполнения передают ключи меньшей стороны соединения в сканирование таблицы фактов.

Неудачные варианты применения

  • BloomFilter для столбцов с малым числом уникальных значений (флаги состояния, пол). Фильтр всё равно пропускает почти каждую страницу, а место для его хранения расходуется впустую. Используйте встроенный ZoneMap или вовсе откажитесь от индекса.
  • BloomFilter для предикатов диапазона. BloomFilter отвечает на вопрос «входит ли X в множество?», а не «меньше ли X, чем Y?». Для фильтров диапазона используется ZoneMap.
  • Бакетирование по столбцу, по которому вы не фильтруете данные. Вы несёте затраты на хеш-распределение при записи, но не получаете отсечения при чтении. Выбирайте ключ бакетирования, соответствующий наиболее избирательному предикату равенства.
  • Одна огромная партиция для всех данных. Планировщику нечего исключать, и компенсировать это приходится только отсечением таблетов и сегментов. Партиционируйте по столбцу, по которому запросы действительно фильтруют данные, обычно по времени.
  • Использование BloomFilter вместо полнотекстового поиска. Для поиска фраз или токенов используйте инвертированный индекс; BloomFilter обрабатывает только равенство.

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