多くのデータベースと同様に、 データをパーティションに分割し、パーティションをさらにバケットに分割します。パーティションは通常、時間またはその他の連続値によって定義されます。これにより、クエリ エンジンは、無関係なデータ範囲をプルーニングすることで、クエリ中にターゲット データをすばやく見つけることができます。
一方、バケット化では、1 つ以上の列のハッシュ値に基づいてデータを分散し、データの偏りを防ぎます。
: ユーザーはテーブル作成ステートメントでパーティションを指定するか、後で DDL ステートメントを使用してパーティションを変更します。
: システムは、データの取り込み時間に基づいて、事前に定義された範囲内でパーティションを自動的に維持します。
Apache Doris 2.1.0 では、 が導入されました。RANGE または LIST によるデータのパーティション分割をサポートし、自動パーティション分割の柔軟性をさらに高めます。
Doris では、データ テーブルは階層的にパーティションに分割され、さらにバケットに分割されます。同じバケット内のデータはデータタブレットを形成します。これは、データ レプリケーション、クラスター間データ スケジューリング、および負荷分散のための Doris の最小物理ストレージ ユニットです。
CREATE TABLE IF NOT EXISTS example_range_tbl ( `user_id` LARGEINT NOT NULL COMMENT "User ID", `date` DATE NOT NULL COMMENT "Data import date", `timestamp` DATETIME NOT NULL COMMENT "Data import timestamp", `city` VARCHAR(20) COMMENT "Location of user", `age` SMALLINT COMMENT "Age of user", `sex` TINYINT COMMENT "Sex of user", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "Last visit date of user", `cost` BIGINT SUM DEFAULT "0" COMMENT "User consumption", `max_dwell_time` INT MAX DEFAULT "0" COMMENT "Maximum dwell time of user", `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "Minimum dwell time of user" ) ENGINE=OLAP AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) PARTITION BY RANGE(`date`) ( PARTITION `p201701` VALUES LESS THAN ("2017-02-01"), PARTITION `p201702` VALUES LESS THAN ("2017-03-01"), PARTITION `p201703` VALUES LESS THAN ("2017-04-01"), PARTITION `p2018` VALUES [("2018-01-01"), ("2019-01-01")) ) DISTRIBUTED BY HASH(`user_id`) BUCKETS 16 PROPERTIES ( "replication_num" = "1" );
テーブルはデータのインポート日date
によってパーティション分割されており、4 つのパーティションが事前に作成されています。各パーティション内では、データはuser_id
のハッシュ値に基づいてさらに 16 個のバケットに分割されます。
このパーティション分割とバケット分割の設計により、2018 年以降のデータをクエリする場合、システムはp2018
パーティションのみをスキャンする必要があります。クエリ SQL は次のようになります。
mysql> desc select count() from example_range_tbl where date >= '20180101'; +--------------------------------------------------------------------------------------+ | Explain String(Nereids Planner) | +--------------------------------------------------------------------------------------+ | PLAN FRAGMENT 0 | | OUTPUT EXPRS: | | count(*)[#11] | | PARTITION: UNPARTITIONED | | | | ...... | | | | 0:VOlapScanNode(193) | | TABLE: test.example_range_tbl(example_range_tbl), PREAGGREGATION: OFF. | | PREDICATES: (date[#1] >= '2018-01-01') | | partitions=1/4 (p2018), tablets=16/16, tabletList=561490,561492,561494 ... | | cardinality=0, avgRowSize=0.0, numNodes=1 | | pushAggOp=NONE | | | +--------------------------------------------------------------------------------------+
データがパーティション間で不均等に分散されている場合、ハッシュベースのバケット化メカニズムは、 user_id
に基づいてデータをさらに分割できます。これにより、クエリとストレージ中に一部のマシンで負荷の不均衡が発生するのを防ぐことができます。
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_200001 VALUES [('2000-01-01'), ('2000-02-01')), PARTITION p_200002 VALUES [('2000-02-01'), ('2000-03-01')), PARTITION p_200003 VALUES [('2000-03-01'), ('2000-04-01')), PARTITION p_200004 VALUES [('2000-04-01'), ('2000-05-01')), PARTITION p_200005 VALUES [('2000-05-01'), ('2000-06-01')), PARTITION p_200006 VALUES [('2000-06-01'), ('2000-07-01')), PARTITION p_200007 VALUES [('2000-07-01'), ('2000-08-01')), PARTITION p_200008 VALUES [('2000-08-01'), ('2000-09-01')), PARTITION p_200009 VALUES [('2000-09-01'), ('2000-10-01')), PARTITION p_200010 VALUES [('2000-10-01'), ('2000-11-01')), PARTITION p_200011 VALUES [('2000-11-01'), ('2000-12-01')), PARTITION p_200012 VALUES [('2000-12-01'), ('2001-01-01')), PARTITION p_200101 VALUES [('2001-01-01'), ('2001-02-01')), ...... ) DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 PROPERTIES ( ...... );
これは、日ごとにパーティション化されたテーブルに対する CREATE TABLE ステートメントの例です。 start
パラメータとend
パラメータはそれぞれ-7
と3
に設定されており、次の 3 日間のデータ パーティションが事前に作成され、7 日より古い履歴パーティションが再利用されることを意味します。
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`) () DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 PROPERTIES ( "dynamic_partition.enable" = "true", "dynamic_partition.time_unit" = "DAY", "dynamic_partition.start" = "-7", "dynamic_partition.end" = "3", "dynamic_partition.prefix" = "p", "dynamic_partition.buckets" = "10" );
時間が経つにつれて、テーブルは常に[current date - 7, current date + 3]
の範囲内でパーティションを維持します。動的パーティションは、ODS (Operational Data Store) レイヤーが Kafka などの外部ソースからデータを直接受信する場合など、リアルタイムのデータ取り込みシナリオに特に役立ちます。
start
パラメータとend
パラメータはパーティションの固定範囲を定義し、ユーザーはこの範囲内でのみパーティションを管理できます。ただし、ユーザーがより多くの履歴データを含める必要がある場合は、 start
値を上げる必要があり、クラスターで不要なメタデータのオーバーヘッドが発生する可能性があります。
前者は自動化を意味し、後者は柔軟性を意味します。これら両方を実現するための本質は、パーティションの作成を実際のデータに関連付けることです。
AUTO PARTITION BY RANGE (FUNC_CALL_EXPR) () FUNC_CALL_EXPR ::= DATE_TRUNC ( <partition_column>, '<interval>' )
上記の<partition_column>
はパーティション列 (つまり、パーティション分割の基になる列) です。 <interval>
パーティション単位 (各パーティションの希望する幅) を指定します。
たとえば、パーティション列がk0
で、月ごとにパーティション分割する場合、パーティション ステートメントはAUTO PARTITION BY RANGE (DATE_TRUNC(k0, 'month'))
になります。インポートされたすべてのデータに対して、システムはDATE_TRUNC(k0, 'month')
を呼び出してパーティションの左端を計算し、次に 1 つのinterval
を追加して右端を計算します。
ここで、前の動的パーティションのセクションで紹介したDAILY_TRADE_VALUE
テーブルに自動パーティションを適用できます。
CREATE TABLE DAILY_TRADE_VALUE ( `TRADE_DATE` DATEV2 NOT NULL COMMENT 'Trade Date', `TRADE_ID` VARCHAR(40) NOT NULL COMMENT 'Trade ID', ...... ) AUTO PARTITION BY RANGE (DATE_TRUNC(`TRADE_DATE`, 'month')) () DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 PROPERTIES ( ...... );
mysql> show partitions from DAILY_TRADE_VALUE; Empty set (0.10 sec) mysql> insert into DAILY_TRADE_VALUE values ('2015-01-01', 1), ('2020-01-01', 2), ('2024-03-05', 10000), ('2024-03-06', 10001); Query OK, 4 rows affected (0.24 sec) {'label':'label_2a7353a3f991400e_ae731988fa2bc568', 'status':'VISIBLE', 'txnId':'85097'} mysql> show partitions from DAILY_TRADE_VALUE; +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 588395 | p200 | 2 | 2024-06-01 19:02:40 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2015-01-01]; ..types: [DATEV2]; keys: [2015-02-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 588437 | p20200101000000 | 2 | 2024-06-01 19:02:40 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2020-01-01]; ..types: [DATEV2]; keys: [2020-02-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 588416 | p20240301000000 | 2 | 2024-06-01 19:02:40 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2024-03-01]; ..types: [DATEV2]; keys: [2024-04-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.09 sec)
LIST による自動パーティションは、 region
やdepartment
などの時間ベースではないディメンションに基づいてデータを分割します。これは、LIST によるデータ パーティション分割をサポートしていない動的パーティションのギャップを埋めます。
AUTO PARTITION BY LIST (`partition_col`) ()
これはcity
パーティション列として使用して、LIST による自動パーティション分割を行う例です。
mysql> CREATE TABLE `str_table` ( -> `city` VARCHAR NOT NULL, -> ...... -> ) -> DUPLICATE KEY(`city`) -> AUTO PARTITION BY LIST (`city`) -> () -> DISTRIBUTED BY HASH(`city`) BUCKETS 10 -> PROPERTIES ( -> ...... -> ); Query OK, 0 rows affected (0.09 sec) mysql> insert into str_table values ("Denver"), ("Boston"), ("Los_Angeles"); Query OK, 3 rows affected (0.25 sec) mysql> show partitions from str_table; +-------------+-----------------+----------------+---------------------+--------+--------------+-------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+-----------------+----------------+---------------------+--------+--------------+-------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 589685 | pDenver7 | 2 | 2024-06-01 20:12:37 | NORMAL | city | [types: [VARCHAR]; keys: [Denver]; ] | city | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 589643 | pLos5fAngeles11 | 2 | 2024-06-01 20:12:37 | NORMAL | city | [types: [VARCHAR]; keys: [Los_Angeles]; ] | city | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 589664 | pBoston8 | 2 | 2024-06-01 20:12:37 | NORMAL | city | [types: [VARCHAR]; keys: [Boston]; ] | city | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+-----------------+----------------+---------------------+--------+--------------+-------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.10 sec)
履歴パーティションを手動で調整する
リアルタイム データと按时的な履歴更新时间の両方を受信するテーブルの場合、自動パーティションでは履歴パーティションが自動的に再进行されないため、次の 2 つのオプションをお勧めします。
自動パーティション機能を使用して、履歴更新に対応するLESS THAN
パーティションを手動で作成します。これにより、履歴データとリアルタイム データが明確に分離され、データ管理が容易になります。
mysql> CREATE TABLE DAILY_TRADE_VALUE -> ( -> `TRADE_DATE` DATEV2 NOT NULL COMMENT 'Trade Date', -> `TRADE_ID` VARCHAR(40) NOT NULL COMMENT 'Trade ID' -> ) -> AUTO PARTITION BY RANGE (DATE_TRUNC(`TRADE_DATE`, 'DAY')) -> ( -> PARTITION `pHistory` VALUES LESS THAN ("2024-01-01") -> ) -> DISTRIBUTED BY HASH(`TRADE_DATE`) BUCKETS 10 -> PROPERTIES -> ( -> "replication_num" = "1" -> ); Query OK, 0 rows affected (0.11 sec) mysql> insert into DAILY_TRADE_VALUE values ('2015-01-01', 1), ('2020-01-01', 2), ('2024-03-05', 10000), ('2024-03-06', 10001); Query OK, 4 rows affected (0.25 sec) {'label':'label_96dc3d20c6974f4a_946bc1a674d24733', 'status':'VISIBLE', 'txnId':'85092'} mysql> show partitions from DAILY_TRADE_VALUE; +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 577871 | pHistory | 2 | 2024-06-01 08:53:49 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [0000-01-01]; ..types: [DATEV2]; keys: [2024-01-01]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577940 | p20240305000000 | 2 | 2024-06-01 08:53:49 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2024-03-05]; ..types: [DATEV2]; keys: [2024-03-06]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577919 | p20240306000000 | 2 | 2024-06-01 08:53:49 | NORMAL | TRADE_DATE | [types: [DATEV2]; keys: [2024-03-06]; ..types: [DATEV2]; keys: [2024-03-07]; ) | TRADE_DATE | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+-----------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.10 sec)
NULLパーティション
Auto Partition by LIST を适用すると、Doris は NULL パーティションに NULL 値を格納することをサポートします。例:
mysql> CREATE TABLE list_nullable -> ( -> `str` varchar NULL -> ) -> AUTO PARTITION BY LIST (`str`) -> () -> DISTRIBUTED BY HASH(`str`) BUCKETS auto -> PROPERTIES -> ( -> "replication_num" = "1" -> ); Query OK, 0 rows affected (0.10 sec) mysql> insert into list_nullable values ('123'), (''), (NULL); Query OK, 3 rows affected (0.24 sec) {'label':'label_f5489769c2f04f0d_bfb65510f9737fff', 'status':'VISIBLE', 'txnId':'85089'} mysql> show partitions from list_nullable; +-------------+---------------+----------------+---------------------+--------+--------------+------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables | +-------------+---------------+----------------+---------------------+--------+--------------+------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ | 577297 | pX | 2 | 2024-06-01 08:19:21 | NORMAL | str | [types: [VARCHAR]; keys: [NULL]; ] | str | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577276 | p0 | 2 | 2024-06-01 08:19:21 | NORMAL | str | [types: [VARCHAR]; keys: []; ] | str | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | | 577255 | p1233 | 2 | 2024-06-01 08:19:21 | NORMAL | str | [types: [VARCHAR]; keys: [123]; ] | str | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | NULL | +-------------+---------------+----------------+---------------------+--------+--------------+------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+----------+------------+-------------------------+-----------+--------------------+--------------+ 3 rows in set (0.11 sec)
ただし、RANGE による自動パーティションは NULL パーティションをサポートしていません。これは、NULL 値が最小のLESS THAN
パーティションに格納され、適切な範囲を確実に判断できないためです。自動パーティションが (-INFINITY、MIN_VALUE) の範囲で NULL パーティションを作成すると、MIN_VALUE 境界が意図したビジネス ロジックを正確に表さない可能性があるため、このパーティションが本番環境で誤って削除されるリスクがあります。
LIST による自動パーティションは、複数の列に基づくパーティション分割をサポートしますが、自動的に作成される各パーティションには単一の値のみが含まれ、パーティション名の長さは 50 文字を超えることはできません。パーティション名は特定の命名規則に従うことに注意してください。これは、メタデータ管理に特別な影響を及ぼします。つまり、50 文字のスペースのすべてをユーザーが自由に使用できるわけではありません。
RANGE による自動パーティションは、単一のパーティション列のみをサポートし、その型はDATEまたはDATETIMEである必要があります。
LIST による自動パーティションは、 NULLABLEパーティション列と NULL 値の挿入をサポートします。RANGE による自動パーティションは、NULLABLE パーティション列をサポートしません。
これまで、自動パーティション機能がない場合、テーブルに必要なパーティションがない場合、Doris の動作では、 DATA_QUALITY_ERROR
が報告されるまで BE ノードがエラーを蓄積していました。自動パーティション機能を有効にすると、必要なパーティションをオンザフライで作成するように Doris フロントエンドに要求が送信されます。パーティション作成トランザクションが完了すると、Doris フロントエンドはコーディネーターに応答し、コーディネーターは対応する通信チャネル (ノード チャネルとタブレット チャネル) を開いて、データ取り込みプロセスを続行します。これは、ユーザーにとってシームレスなエクスペリエンスです。
ケース 1 : フロントエンド 1 つ + バックエンド 3 つ。ランダムに生成されたデータセット 6 つ (それぞれ 1 億行、2,000 パーティション)。6 つのデータセットを 6 つのテーブルに同時に取り込みました。
目的: 高圧下での自動パーティションのパフォーマンスを評価し、パフォーマンスの低下がないか確認します。
結果: 自動パーティションにより、平均パフォーマンスの低下は 5% 未満となり、すべてのインポート トランザクションが安定して実行されます。
ケース 2 : フロントエンド 1 つ + バックエンド 3 つ。ルーチン ロードによって Flink から 1 秒あたり 100 行を取り込み、それぞれ 1、10、20 の同時トランザクション (テーブル) でテストします。
目的: さまざまな同時実行レベルでの自動パーティションで発生する可能性のあるデータ バックログの問題を特定します。
結果: 自動パーティションの有効/無効に関係なく、CPU 使用率が 100% 近くに達した 20 件の同時トランザクションでも、テストしたすべての同時実行レベルでバックプレッシャーの問題が発生することなく、データの取り込みは成功しました。