Бакетирование данных
Партицию можно дополнительно разделить на несколько бакетов данных в соответствии с требованиями бизнеса. Каждый бакет хранится как физический фрагмент данных (Tablet). Продуманная стратегия бакетирования позволяет существенно сократить объём данных, сканируемых во время запроса, повысить производительность запросов и увеличить возможности параллельной обработки.
Этот документ организован по пути принятия решений при создании таблицы: сначала выбирается способ бакетирования, затем ключ бакетирования и наконец количество бакетов и последующий подход к обслуживанию.
Быстрый выбор
При создании таблицы дизайн бакетирования можно выполнить в следующем порядке:
| Шаг | Решение | Ключевые факторы |
|---|---|---|
| 1 | Выбрать способ бакетирования | Наличие столбцов, часто используемых для фильтрации, равномерность данных и модель таблицы |
| 2 | Выбрать ключ бакетирования (только для Hash-бакетирования) | Условия фильтрации запросов, кардинальность столбцов, характеристики параллелизма и пропускной способности запросов |
| 3 | Определить количество бакетов | Размер данных в каждом Tablet, количество BE и дисков |
| 4 | Спланировать стратегию обслуживания бакетов | Тенденция роста данных и использование динамического партиционирования |
1. Выбор способа бакетирования
Doris поддерживает два способа бакетирования: Hash-бакетирование и Random-бакетирование. Их основные различия представлены ниже:
| Критерий сравнения | Hash-бакетирование | Random-бакетирование |
|---|---|---|
| Способ распределения данных | Разделение по значению Hash ключа бакетирования | Случайное равномерное распределение |
| Требуется ли ключ бакетирования | Да | Нет |
| Поддерживается ли отсечение бакетов | Да | Нет |
| Поддерживаемые модели таблиц | DUPLICATE / UNIQUE / AGGREGATE | Только DUPLICATE |
| Риск перекоса данных | Зависит от выбора ключа бакетирования | Ниже |
| Сценарии применения | Точечные запросы с частой фильтрацией по определённому столбцу | Анализ по произвольным измерениям и данные, склонные к перекосу |
1. Hash-бакетирование
При создании таблицы или добавлении новой партиции необходимо выбрать один или несколько столбцов в качестве ключа бакетирования и явно указать количество бакетов. В одной партиции система вычисляет Hash на основе ключа бакетирования и количества бакетов, а строки с одинаковым значением Hash назначаются в один бакет.
Например, на рисунке ниже партиция p250102 разделена на 3 бакета по столбцу region, а строки с одинаковым значением Hash помещены в один бакет.

Рекомендуемые сценарии:
- Если бизнес часто фильтрует данные по определённому полю, это поле можно использовать как ключ бакетирования и повысить эффективность запросов за счёт отсечения бакетов.
- Данные в таблице распределены относительно равномерно и вероятность перекоса невелика.
Пример: создание таблицы с Hash-бакетированием. Подробный синтаксис см. в разделе CREATE TABLE.
В примерах ниже имена таблиц указаны с базой данных demo; если в кластере она отсутствует, сначала создайте её:
CREATE DATABASE IF NOT EXISTS demo;
CREATE TABLE demo.hash_bucket_tbl(
oid BIGINT,
dt DATE,
region VARCHAR(10),
amount INT
)
DUPLICATE KEY(oid)
PARTITION BY RANGE(dt) (
PARTITION p250101 VALUES LESS THAN("2025-01-01"),
PARTITION p250102 VALUES LESS THAN("2025-01-02")
)
DISTRIBUTED BY HASH(region) BUCKETS 8;
В этом примере DISTRIBUTED BY HASH(region) задаёт Hash-бакетирование и выбирает столбец region в качестве ключа бакетирования. BUCKETS 8 задаёт создание 8 бакетов.
2. Random-бакетирование
Random-бакетирование случайным образом распределяет данные по бакетам внутри каждой партиции, не используя значение Hash какого-либо поля. Такой подход обеспечивает равномерное распределение данных и предотвращает перекос, вызванный неудачным выбором ключа бакетирования.
При загрузке данных каждая партия в рамках одного задания загрузки случайным образом записывается в Tablet, что обеспечивает равномерное распределение данных. Например, на рисунке ниже 8 партий данных случайным образом распределены по 3 бакетам в партиции p250102.

При использовании Random-бакетирования можно включить режим загрузки в один Tablet (установить load_to_single_tablet в true), чтобы данные одной партии записывались только в один фрагмент данных. Это позволяет:
- Повысить параллелизм и пропускную способность крупномасштабных загрузок данных.
- Сократить усиление записи, вызванное операциями загрузки данных и Compaction.
- Повысить стабильность кластера.
Рекомендуемые сценарии:
- Анализ по произвольным измерениям, когда в бизнесе нет фиксированных столбцов фильтрации или соединения.
- Распределение данных часто запрашиваемых столбцов или комбинаций столбцов крайне неравномерно, поэтому необходимо избежать перекоса данных.
Неподходящие сценарии:
- Точечные запросы: Random-бакетирование не выполняет отсечение по ключу бакетирования, поэтому сканируются все данные в совпавших партициях.
- Таблицы UNIQUE и AGGREGATE: Random-бакетирование поддерживается только таблицами DUPLICATE.
Пример: создание таблицы с Random-бакетированием. Подробный синтаксис см. в разделе CREATE TABLE.
CREATE TABLE demo.random_bucket_tbl(
oid BIGINT,
dt DATE,
region VARCHAR(10),
amount INT
)
DUPLICATE KEY(oid)
PARTITION BY RANGE(dt) (
PARTITION p250101 VALUES LESS THAN("2025-01-01"),
PARTITION p250102 VALUES LESS THAN("2025-01-02")
)
DISTRIBUTED BY RANDOM BUCKETS 8;
В этом примере DISTRIBUTED BY RANDOM задаёт Random-бакетирование без выбора ключа бакетирования. BUCKETS 8 задаёт создание 8 бакетов.
2. Выбор ключа бакетирования
Только Hash-бакетирование требует выбора ключа бакетирования. Для Random-бакетирования ключ не требуется.
Ключ бакетирования может состоять из одного или нескольких столбцов. Разные модели таблиц накладывают на ключ бакетирования следующие ограничения:
| Модель таблицы | Допустимые ключи бакетирования |
|---|---|
| DUPLICATE | Любой столбец Key или Value |
| AGGREGATE / UNIQUE | Только столбцы Key (для обеспечения корректного агрегирования данных) |
Принципы выбора
При выборе ключа бакетирования с учётом характеристик бизнес-запросов можно руководствоваться следующими принципами:
| Принцип | Описание | Преимущество |
|---|---|---|
| Использовать условия фильтрации запросов | Выбирать в качестве ключа бакетирования столбцы, которые часто используются в фильтрах запросов | Поддержка отсечения бакетов и сокращение объёма сканируемых данных |
| Использовать столбцы с высокой кардинальностью | Выбирать в качестве ключа бакетирования столбцы с большим количеством различных значений | Равномерное распределение данных и предотвращение перекоса |
| Сценарии высокопараллельных точечных запросов | Выбирать один столбец или небольшое количество столбцов в качестве ключа бакетирования | Один запрос сканирует только один бакет, что уменьшает влияние операций ввода-вывода между запросами |
| Сценарии запросов с высокой пропускной способностью | Выбирать несколько столбцов в качестве ключа бакетирования | Данные распределяются равномернее; если условия запроса не могут полностью сопоставиться с условиями равенства, повышается общая пропускная способность |
3. Определение количества бакетов
В Doris каждый Bucket хранится как физический файл (Tablet). Общее количество Tablet в таблице равно:
Total Tablets = partition_num × bucket_num
После задания количества бакетов для Partition изменить его нельзя. При определении количества бакетов заранее учитывайте будущее расширение машин.
Начиная с версии 2.0 Doris поддерживает автоматическую установку количества бакетов в партиции на основе ресурсов машин и информации о кластере. В зависимости от требуемой точности оценки можно выбрать ручной или автоматический способ.
1. Ручная установка количества бакетов
Количество бакетов задаётся с помощью предложения DISTRIBUTED:
-- Set hash bucket num to 8
DISTRIBUTED BY HASH(region) BUCKETS 8
-- Set random bucket num to 8
DISTRIBUTED BY RANDOM BUCKETS 8
Принципы принятия решения
При определении количества бакетов соблюдайте следующие два принципа. Если они противоречат друг другу, приоритет имеет принцип размера:
-
Принцип размера: рекомендуется, чтобы размер сжатых данных каждого Tablet (без индексов) составлял от 1 GB до 20 GB, а для таблиц Unique Key — не более 10 GB.
- Слишком маленькие Tablet: агрегирование менее эффективно, а нагрузка на управление метаданными возрастает.
- Слишком большие Tablet: усложняются миграция и восстановление реплик, а стоимость повторной попытки неудачного Schema Change увеличивается.
- Фактический размер Tablet можно проверить с помощью
SHOW TABLETS FROM your_table.
-
Принцип количества: без учёта масштабирования рекомендуется, чтобы количество Tablet в таблице было немного больше общего количества дисков в кластере.
Для таблиц MOW Unique Key следует учитывать не только размер сжатых данных, но и физическое количество строк в каждом Tablet. Base Compaction создаёт карту преобразования rowid для физических входных строк, участвующих в слиянии; основное хранилище сопоставления занимает примерно 8 байт на строку. В узких таблицах или таблицах с высокой степенью сжатия во время Compaction может закончиться память из-за большого количества строк, даже если размер Tablet соответствует приведённым выше рекомендациям. Оценки и рекомендации по устранению проблемы см. в разделе Накладные расходы памяти Compaction для больших MOW Tablet.
Кроме того, учитывайте следующее:
- Количество бакетов должно быть целым кратным количеству BE, чтобы обеспечить равномерное распределение данных.
- Количество бакетов в одной партиции обычно не должно превышать 128. Если требуется больше, сначала разделите таблицу на партиции.
Примеры рекомендуемой конфигурации
Предположим, что в кластере 10 машин BE и на каждой машине по одному диску. Количество бакетов можно задать по следующей таблице:
| Размер сжатых данных партиции | Рекомендуемое количество бакетов |
|---|---|
| < 1 GB | 1 бакет |
| 1 - 10 GB | 10 бакетов |
| 10 - 200 GB | 10 - 20 бакетов |
| > 200 GB | Сначала разделить таблицу на партиции |
Размер данных таблицы можно проверить командой SHOW DATA. Полученный результат необходимо разделить на количество реплик, чтобы получить фактический размер данных таблицы.
2. Автоматическая установка количества бакетов
Функция автоматического вывода количества бакетов прогнозирует будущий размер партиций на основе размеров партиций за недавний период и соответствующим образом определяет количество бакетов.
-- Set hash bucket auto
DISTRIBUTED BY HASH(region) BUCKETS AUTO
properties("estimate_partition_size" = "20G")
-- Set random bucket auto
DISTRIBUTED BY RANDOM BUCKETS AUTO
properties("estimate_partition_size" = "20G")
Свойство estimate_partition_size используется для корректировки первоначальной оценки размера партиции:
- Параметр необязателен. Если он не указан, значение по умолчанию —
10GB. - Параметр влияет только на первоначальную оценку и не зависит от будущего размера партиции, который система позже выводит из исторических данных партиций.
Рассчитанное количество бакетов ограничивается конфигурациями FE autobucket_min_buckets и autobucket_max_buckets:
| Конфигурация FE | По умолчанию | Описание |
|---|---|---|
autobucket_min_buckets | 3 | Нижняя граница результата автоматического бакетирования. В серии 4.0 значение по умолчанию изменено с 1 на 3 начиная с версии 4.0.8, а в серии 4.1 — начиная с версии 4.1.4 |
autobucket_max_buckets | 128 | Верхняя граница результата автоматического бакетирования |
Значение по умолчанию autobucket_min_buckets изменено с 1 на 3 в версии 4.0.8 (серия 4.0) и версии 4.1.4 (серия 4.1). Ранее для небольшой партиции мог быть рассчитан один бакет, что приводило к недостаточному параллелизму и неравномерному распределению данных. После изменения автоматическое бакетирование никогда не создаёт меньше 3 бакетов.
Изменение влияет только на партиции, созданные после обновления; количество бакетов в существующих партициях не меняется. Чтобы сохранить прежнее поведение, явно установите autobucket_min_buckets обратно в 1.
4. Обслуживание бакетирования данных
В настоящее время Doris поддерживает изменение количества бакетов только для вновь добавляемых партиций. Следующие операции не поддерживаются:
- Изменение типа бакетирования не поддерживается.
- Изменение ключа бакетирования не поддерживается.
- Изменение количества бакетов для уже созданных бакетов не поддерживается.
При создании таблицы количество бакетов для каждой партиции единообразно задаётся предложением DISTRIBUTED. Чтобы учитывать рост или уменьшение объёма данных, при динамическом добавлении партиций можно отдельно указать количество бакетов для новой партиции.
В следующих примерах показано, как изменить количество бакетов для вновь добавляемых партиций с помощью команды ALTER TABLE:
-- Modify hash bucket table
ALTER TABLE demo.hash_bucket_tbl
ADD PARTITION p250103 VALUES LESS THAN("2025-01-03")
DISTRIBUTED BY HASH(region) BUCKETS 16;
-- Modify random bucket table
ALTER TABLE demo.random_bucket_tbl
ADD PARTITION p250103 VALUES LESS THAN("2025-01-03")
DISTRIBUTED BY RANDOM BUCKETS 16;
-- Modify dynamic partition table
ALTER TABLE demo.dynamic_partition_tbl
SET ("dynamic_partition.buckets"="16");
После изменения количества бакетов результат можно проверить командой SHOW PARTITION.