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

Автоматическое партиционирование

Автоматическое партиционирование (AUTO PARTITION) позволяет Doris автоматически создавать партиции при загрузке данных на основе значений столбца партиционирования. Оно решает следующие проблемы:

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

Doris поддерживает два типа автоматического партиционирования:

ТипСпособ партиционированияФункция партиционированияПоддерживаемые типы столбцов партиционирования
AUTO RANGE PARTITIONАвтоматическое партиционирование по диапазонуdate_truncDATE, DATETIME, TIMESTAMP_NS
AUTO LIST PARTITIONАвтоматическое партиционирование по перечисляемым значениямВызовы функций не поддерживаютсяBOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, TIMESTAMP_NS, CHAR, VARCHAR

Сценарии использования​

Рассмотрим столбец партиционирования с временным типом данных:

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

В таких случаях ни динамическое партиционирование, ни создание партиций вручную не решают задачу, а автоматическое партиционирование хорошо подходит для этих сценариев.

Пример сценария: таблица истории сделок​

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

CREATE TABLE `DAILY_TRADE_VALUE`
(
`TRADE_DATE` datev2 NOT NULL COMMENT 'Trade date',
`TRADE_ID` varchar(40) NOT NULL COMMENT 'Trade ID',
......
)
UNIQUE KEY(`TRADE_DATE`, `TRADE_ID`)
PARTITION BY RANGE(`TRADE_DATE`)
(
PARTITION p_2000 VALUES [('2000-01-01'), ('2001-01-01')),
PARTITION p_2001 VALUES [('2001-01-01'), ('2002-01-01')),
PARTITION p_2002 VALUES [('2002-01-01'), ('2003-01-01')),
PARTITION p_2003 VALUES [('2003-01-01'), ('2004-01-01')),
PARTITION p_2004 VALUES [('2004-01-01'), ('2005-01-01')),
PARTITION p_2005 VALUES [('2005-01-01'), ('2006-01-01')),
PARTITION p_2006 VALUES [('2006-01-01'), ('2007-01-01')),
PARTITION p_2007 VALUES [('2007-01-01'), ('2008-01-01')),
PARTITION p_2008 VALUES [('2008-01-01'), ('2009-01-01')),
PARTITION p_2009 VALUES [('2009-01-01'), ('2010-01-01')),
PARTITION p_2010 VALUES [('2010-01-01'), ('2011-01-01')),
PARTITION p_2011 VALUES [('2011-01-01'), ('2012-01-01')),
PARTITION p_2012 VALUES [('2012-01-01'), ('2013-01-01')),
PARTITION p_2013 VALUES [('2013-01-01'), ('2014-01-01')),
PARTITION p_2014 VALUES [('2014-01-01'), ('2015-01-01')),
PARTITION p_2015 VALUES [('2015-01-01'), ('2016-01-01')),
PARTITION p_2016 VALUES [('2016-01-01'), ('2017-01-01')),
PARTITION p_2017 VALUES [('2017-01-01'), ('2018-01-01')),
PARTITION p_2018 VALUES [('2018-01-01'), ('2019-01-01')),
PARTITION p_2019 VALUES [('2019-01-01'), ('2020-01-01')),
PARTITION p_2020 VALUES [('2020-01-01'), ('2021-01-01')),
PARTITION p_2021 VALUES [('2021-01-01'), ('2022-01-01'))
)
DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);

У этого подхода есть следующие недостатки:

  1. При создании таблицы необходимо вручную перечислить все партиции.
  2. При изменении диапазона значений столбца партиционирования (например, при добавлении данных за 2022 год) партиции приходится изменять с помощью ALTER-TABLE-PARTITION, что неудобно.
  3. Если требуется изменить партиции или использовать более мелкую гранулярность, это потребует значительных усилий.

При использовании AUTO PARTITION DDL можно упростить до следующего:

CREATE TABLE `DAILY_TRADE_VALUE`
(
`TRADE_DATE` datev2 NOT NULL,
`TRADE_ID` varchar(40) NOT NULL,
......
)
UNIQUE KEY(`TRADE_DATE`, `TRADE_ID`)
AUTO PARTITION BY RANGE (date_trunc(`TRADE_DATE`, 'year'))
(
)
DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10
PROPERTIES (
"replication_num" = "1"
);

В только что созданной таблице нет партиций по умолчанию:

show partitions from `DAILY_TRADE_VALUE`;
Empty set (0.12 sec)

После вставки данных соответствующие партиции создаются автоматически:

insert into `DAILY_TRADE_VALUE` values ('2012-12-13', 1), ('2008-02-03', 2), ('2014-11-11', 3);

show partitions from `DAILY_TRADE_VALUE`;
+-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+
| PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable |
+-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+
| 180060 | p20080101000000 | 2 | 2023-09-18 21:49:29 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2008-01-01]; ..types: [DATEV2]; keys: [2009-01-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true |
| 180039 | p20120101000000 | 2 | 2023-09-18 21:49:29 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2012-01-01]; ..types: [DATEV2]; keys: [2013-01-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true |
| 180018 | p20140101000000 | 2 | 2023-09-18 21:49:29 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2014-01-01]; ..types: [DATEV2]; keys: [2015-01-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true |
+-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+

Партиции, созданные автоматически, функционально идентичны партициям, созданным вручную.

Синтаксис​

Используйте следующий синтаксис в части partitions_definition оператора CREATE-TABLE.

AUTO RANGE PARTITION​

[AUTO] PARTITION BY RANGE(<partition_expr>)
<origin_partitions_definition>

Где:

partition_expr ::= date_trunc(<partition_column>, '<interval>')
подсказка

В AUTO RANGE PARTITION ключевое слово AUTO можно опустить; автоматическое партиционирование при этом сохраняется.

Пример:

CREATE TABLE `date_table` (
`TIME_STAMP` datev2 NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`TIME_STAMP`)
AUTO PARTITION BY RANGE (date_trunc(`TIME_STAMP`, 'month'))
(
)
DISTRIBUTED BY HASH(`TIME_STAMP`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

AUTO LIST PARTITION​

AUTO PARTITION BY LIST(`partition_col1` [, `partition_col2`, ...])
<origin_partitions_definition>

Автоматическое партиционирование LIST поддерживает партиционирование по нескольким столбцам с тем же синтаксисом, что и обычное партиционирование LIST: AUTO PARTITION BY LIST(col1, col2, ...). Для каждого значения столбца партиционирования, у которого ещё нет соответствующей партиции, создаётся отдельная новая партиция.

Пример:

CREATE TABLE `str_table` (
`str` varchar not null
) ENGINE=OLAP
DUPLICATE KEY(`str`)
AUTO PARTITION BY LIST (`str`)
()
DISTRIBUTED BY HASH(`str`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

Сравнение ограничений​

ОграничениеAUTO RANGE PARTITIONAUTO LIST PARTITION
Поддерживаемые функции партиционированияТолько date_truncВызовы функций не поддерживаются
Поддерживаемые типы столбцов партиционированияDATE, DATETIME, TIMESTAMP_NSBOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, TIMESTAMP_NS, CHAR, VARCHAR
Поддержка партиционирования по нескольким столбцамНетДа
Ограничение длины имени партиции-Не более 50 символов (имя формируется путём конкатенации и экранирования содержимого столбцов партиционирования; фактически допустимая длина может быть меньше)
Правило определения значений партицийРазбиение по временному диапазону, полученному усечением с помощью date_truncДля каждого нового перечисляемого значения, у которого ещё нет партиции, создаётся отдельная новая партиция

Партиционирование значений NULL​

После включения переменной сеанса allow_partition_column_nullable два типа автоматического партиционирования различаются по поддержке столбцов NULLABLE:

Тип автоматического партиционированияПоддержка столбца партиционирования NULLABLE
AUTO LIST PARTITIONПоддерживается. При записи NULL создаётся обычная партиция для NULL.
AUTO RANGE PARTITIONНе поддерживается

AUTO LIST PARTITION: поддержка столбцов NULLABLE​

create table auto_null_list(
k0 varchar null
)
auto partition by list (k0)
(
)
DISTRIBUTED BY HASH(`k0`) BUCKETS 1
properties("replication_num" = "1");

insert into auto_null_list values (null);

select * from auto_null_list;
+------+
| k0 |
+------+
| NULL |
+------+

select * from auto_null_list partition(pX);
+------+
| k0 |
+------+
| NULL |
+------+

AUTO RANGE PARTITION: столбцы NULLABLE не поддерживаются​

CREATE TABLE `range_table_nullable` (
`k1` INT,
`k2` DATETIMEV2(3),
`k3` DATETIMEV2(6)
) ENGINE=OLAP
DUPLICATE KEY(`k1`)
AUTO PARTITION BY RANGE (date_trunc(`k2`, 'day'))
()
DISTRIBUTED BY HASH(`k1`) BUCKETS 16
PROPERTIES (
"replication_allocation" = "tag.location.default: 1"
);

ERROR 1105 (HY000): errCode = 2, detailMessage = AUTO RANGE PARTITION doesn't support NULL column

Управление жизненным циклом​

к сведению

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

В таблицах AUTO RANGE PARTITION можно управлять жизненным циклом исторических партиций с помощью свойства partition.retention_count. Это свойство принимает положительное целое число N, означающее, что сохраняются только N исторических партиций с наибольшими значениями партиций; все текущие и будущие партиции сохраняются.

Ограничения использования:

  • Это свойство можно задать только для таблиц AUTO RANGE PARTITION. В противном случае оператор завершается ошибкой Only AUTO RANGE PARTITION table could set partition.retention_count.
  • Его нельзя использовать совместно с уже включённым динамическим партиционированием (dynamic_partition.enable = true). В противном случае оператор завершается ошибкой Can not use partition.retention_count and dynamic_partition properties at the same time. Создание партиций посредством динамического партиционирования и очистка партиций по заданному количеству сохраняемых партиций являются взаимоисключающими режимами планирования. Это ограничение действует начиная с версии 4.1.4 как в режиме с совместным размещением вычислений и хранения, так и в режиме с их разделением.
  • Начиная с версии 4.1.4, режим с разделением вычислений и хранения также поддерживает изменение этого свойства с помощью ALTER TABLE ... SET ("partition.retention_count" = "N"). До версии 4.1.4 эта операция ALTER отклонялась или не давала эффекта в режиме с разделением вычислений и хранения.

Определения понятий​

  • Историческая партиция: партиция, верхняя граница которой меньше или равна текущему времени.
  • Текущая или будущая партиция: партиция, нижняя граница которой больше или равна текущему времени.
  • Сравнение значений партиций: поскольку партиции RANGE никогда не перекрываются, выражение «значение партиции A больше значения партиции B» эквивалентно выражению «нижняя граница партиции A больше верхней границы партиции B», которое также эквивалентно выражению «верхняя граница партиции A больше верхней границы партиции B».

Пример​

create table auto_recycle(
k0 datetime(6) not null
)
AUTO PARTITION BY RANGE (date_trunc(k0, 'day')) ()
DISTRIBUTED BY HASH(`k0`) BUCKETS 1
properties(
"partition.retention_count" = "3"
);

Такая конфигурация означает, что сохраняются только 3 исторические партиции с наибольшими значениями дат. Пусть текущая дата равна 2025-10-21, а данные вставляются за каждый день с 2025-10-16 по 2025-10-23. После одного цикла очистки остаётся 6 партиций, как показано ниже:

Очистка

Список оставшихся партиций:

  • p20251018000000
  • p20251019000000
  • p20251020000000 (эта партиция и партиции выше: сохраняются только три исторические партиции)
  • p20251021000000 (эта партиция и партиции ниже: текущие и будущие партиции остаются без изменений)
  • p20251022000000
  • p20251023000000

Совместное использование с автоматическим распределением по бакетам​

Только AUTO RANGE PARTITION можно использовать совместно с функцией автоматического распределения по бакетам.

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

Примечание

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

Управление партициями​

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

  • Функция auto_partition_name: сопоставляет значение столбца партиционирования с именем партиции.
  • Табличная функция partitions: получает подробные сведения о партиции по её имени.

Продолжая пример с таблицей DAILY_TRADE_VALUE, после вставки данных выполним запрос, чтобы найти партицию, к которой относится конкретная запись:

select * from partitions("catalog"="internal","database"="optest","table"="DAILY_TRADE_VALUE") where PartitionName = auto_partition_name('range', 'year', '2008-02-03');
+-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+-----------+------------+-------------------------+-----------+--------------------+--------------+
| PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables |
+-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+-----------+------------+-------------------------+-----------+--------------------+--------------+
| 127095 | p20080101000000 | 2 | 2024-11-14 17:29:02 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2008-01-01]; ..types: [DATEV2]; keys: [2009-01-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | \N | 985.000 B | 0 | tag.location.default: 1 | 1 | 1 | \N |
+-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+-----------+------------+-------------------------+-----------+--------------------+--------------+

Этот подход позволяет точно выбрать идентификатор и значение каждой партиции для последующих операций над конкретными партициями (например, insert overwrite partition).

Подробное описание синтаксиса:

Примечания​

ПримечаниеОписание
Поддержка партиционирования по нескольким столбцамAUTO LIST PARTITION поддерживает партиционирование по нескольким столбцам с тем же синтаксисом, что и обычное партиционирование LIST.
Партиции, созданные при неудачных загрузках, не очищаются автоматическиЕсли при вставке или загрузке данных создаются партиции, но вся загрузка не завершается (завершается ошибкой или отменяется), созданные партиции не удаляются автоматически.
Использование аналогично обычным партициямДля таблицы, использующей AUTO PARTITION, меняется только способ создания партиций: они создаются автоматически вместо создания вручную. В остальном использование таблицы и её партиций не отличается от таблиц без AUTO PARTITION.
Ограничение максимального количества партицийМаксимальное количество партиций в таблице определяется параметром max_auto_partition_num в конфигурации FE. Настройте его по необходимости, чтобы избежать случайного создания слишком большого количества партиций.
Интервал опроса при отправке данныхПри загрузке данных в таблицу AUTO PARTITION интервал опроса, с которым Coordinator отправляет данные, отличается от интервала для обычных таблиц. Он определяется параметром olap_table_sink_send_interval_auto_partition_factor в конфигурации BE. После включения memtable на узле sink (enable_memtable_on_sink_node = true) эта переменная не действует.
Поведение INSERT OVERWRITEОсобенности поведения таблиц AUTO PARTITION при вставке данных с помощью insert-overwrite описаны в документации INSERT OVERWRITE.
Конфликты метаданных могут приводить к сбоям загрузкиЕсли при создании партиций в ходе загрузки над таблицей выполняются другие операции с метаданными (например, Schema Change или Rebalance), загрузка может завершиться ошибкой.