Sequence-Column

          PALO

          Sequence-Column

          UNIQUE KEY 模型下,Doris 会根据主键自动的进行数据的更新。但是当同一批次导入数据中出现相同主键的行时,Doris 无法判断其先后顺序,则可能出现更新行为不一致的问题

          而在某些数据同步场景下,需要保证数据能够按顺序更新,而 Sequence Column 功能就是为了解决这一问题。

          实现原理

          Sequence Column 仅支持 UNQIUE KEY 模型的表。其原理是在表中增加一个隐藏列 __DORIS_SEQUENCE_COL__ 。该列的类型由用户在建表时指定。

          在导入的源数据中,用户需额外增加一个顺序列,其类型为建表时指定的 __DORIS_SEQUENCE_COL__ 的类型。Doris 内部会根据这个顺序列的值,决定数据的前后顺序,进行数据更新。

          启用 Sequence Column 功能

          该功能是 Doris 3.10 版本之后引入的新功能。

          1. 创建新表

            在创建表时,我们可以通过如下方式设置 Sequence Column:

            CREATE TABLE order_table
            (
                order_id BIGINT,
                order_type VARCHAR(8),
                order_status VARCHAR(32)
            )
            UNIQUE KEY(order_id)
            DISTRIBUTED BY HASH(order_id) BUCKETS 8
            PROPERTIES
            (
                "function_column.sequence_type" = 'Date'
            );

            这里我们在 PROPERTIES 中指定了 Sequence Column 的类型为 Date,即开启了该功能。更多说明,可参阅 CREATE TABLE 命令手册。

          2. 为旧表开启该功能

            对于 3.10 之前版本创建的 UNIQUE KEY 的表,可以通过以下命令开启该功能:

            ALTER TABLE order_table ENABLE FEATURE "SEQUENCE_LOAD"
            WITH PROPERTIES ("function_column.sequence_type" = "Date")

            这个操作本质上是一个 Schema Change 操作,执行后,需通过 SHOW ALTER TABLE COLUMN 查看作业执行进度。

          如果想确定一个表是否已开启标记删除功能,可以通过 设置一个变量来显示隐藏列

          SET show_hidden_columns=true`

          之后使用 DESC tablename,如果输出中有 __DORIS_SEQUENCE_COL__ 列,则表示该表已开启该功能。

          在导入中使用顺序列功能

          在不同的数据导入方式中使用的方式略有不同。该功能目前支持以下数据导入方式:

          具体使用语法请参阅各自的文档,这里仅对不同导入方式进行简单的示例说明。假设原始导入数据如下:

          1000,TYPE#1,PENDING,2020-10-01
          1001,TYPE#2,PAID,2020-10-02
          1002,TYPE#3,PENDING,2020-10-03
          1001,TYPE#2,PENDING,2020-10-01
          1004,TYPE#3,PAID,2020-10-03

          Stream Load

          curl --location-trusted -u root \
          -H "columns: order_id, order_type, order_status, source_sequence"
          -H "function_column.sequence_col: source_sequence" \
          -T data.txt http://host:port/api/example_db/order/_stream_load

          我们在 Header 的 columns 属性中将第四列命名为 source_sequence,之后在 function_column.sequence_col 属性中将该列设置的顺序列。

          这样,源数据中的 1001 这个订单的最终状态将会是 PAID.

          Broker Load

          LOAD LABEL example_db.label1
          (
              DATA INFILE("hdfs://host:port/user/data/*/test.txt")
              INTO TABLE `order`
              COLUMNS TERMINATED BY ","
              (order_id, order_type, order_status, source_sequence)
              ORDER BY source_sequence
          )
          WITH BROKER 'bos'
          (
              ...
          );

          通过 ORDER BY 子句配置顺序列。

          routine load

          CREATE ROUTINE LOAD example_db.job_name ON order 
          COLUMNS(order_id, order_type, order_status, source_sequence),
          ORDER BY source_sequence
          PROPERTIES
          (
              ...
          )
          FROM KAFKA
          (
              ...
          );

          通过 ORDER BY 子句配置顺序列。

          使用示例

          下面以 Stream Load 为例,通过一个实际的示例展示顺序列的使用方式和效果。

          1. 创建支持 Sequence Column 的表

            CREATE TABLE test_table
            (
                user_id     BIGINT,
                date        DATE,
                group_id    BIGINT,
                keyword     VARCHAR(128)
            )
            UNIQUE KEY(user_id, date, group_id)
            DISTRIBUTED BY HASH(user_id, date) BUCKETS 10
            PROPERTIES
            (
                "function_column.sequence_type" = 'Date'
            )

            之后我们可以查看到隐藏列:

            mysql> set show_hidden_columns=true;
            Query OK, 0 rows affected (0.00 sec)
            mysql> desc test_table;
            +------------------------+--------------+------+-------+---------+---------+
            | Field                  | Type         | Null | Key   | Default | Extra   |
            +------------------------+--------------+------+-------+---------+---------+
            | user_id                | BIGINT       | Yes  | true  | NULL    |         |
            | date                   | DATE         | Yes  | true  | NULL    |         |
            | group_id               | BIGINT       | Yes  | true  | NULL    |         |
            | keyword                | VARCHAR(128) | Yes  | false | NULL    | REPLACE |
            | __DORIS_SEQUENCE_COL__ | DATE         | Yes  | false | NULL    | REPLACE |
            +------------------------+--------------+------+-------+---------+---------+
            5 rows in set (0.00 sec)
          2. 正常导入数据

            导入如下数据:

            1,2020-02-22,1,2020-02-22,a
            1,2020-02-22,1,2020-02-22,b
            1,2020-02-22,1,2020-03-05,c
            1,2020-02-22,1,2020-02-26,d
            1,2020-02-22,1,2020-02-22,e
            1,2020-02-22,1,2020-02-22,b

            将 Sequence Column 映射为源数据中的第4列,modify_date 列。

            curl --location-trusted -u root: \
            -H "column_separator: ," \
            -H "columns: user_id, date, group_id, modify_date, keyword" \
            -H "function_column.sequence_col: modify_date" \
            -T testData http://host:port/api/test/test_table/_stream_load

            结果为

            mysql> select * from test_table;
            +---------+------------+----------+---------+
            | user_id | date       | group_id | keyword |
            +---------+------------+----------+---------+
            |       1 | 2020-02-22 |        1 | c       |
            +---------+------------+----------+---------+

            我们也可以查看隐藏列的值:

            mysql> set show_hidden_columns=true;
            Query OK, 0 rows affected (0.01 sec)
            
            mysql> select * from test_table;
            +---------+------------+----------+---------+------------------------+
            | user_id | date       | group_id | keyword | __DORIS_SEQUENCE_COL__ |
            +---------+------------+----------+---------+------------------------+
            |       1 | 2020-02-22 |        1 | c       | 2020-03-05             |
            +---------+------------+----------+---------+------------------------+

            在这次导入中,因 Sequence Column 的值(也就是 modify_date 中的值)中 2020-03-05 为最大值,所以 keyword 列中最终保留了 c

          3. 替换顺序的保证

            上述步骤完成后,接着导入如下数据:

            1,2020-02-22,1,2020-02-22,a
            1,2020-02-22,1,2020-02-23,b

            查询数据

            MySQL [test]> select * from test_table;
            +---------+------------+----------+---------+
            | user_id | date       | group_id | keyword |
            +---------+------------+----------+---------+
            |       1 | 2020-02-22 |        1 | c       |
            +---------+------------+----------+---------+

            由于新导入的数据的 Sequence Column 都小于表中已有的值,则没有替换发生。

            再尝试导入如下数据:

            1,2020-02-22,1,2020-02-22,a
            1,2020-02-22,1,2020-03-23,w

            查询数据:

            MySQL [test]> select * from test_table;
            +---------+------------+----------+---------+
            | user_id | date       | group_id | keyword |
            +---------+------------+----------+---------+
            |       1 | 2020-02-22 |        1 | w       |
            +---------+------------+----------+---------+

            由于新导入的数据的 Sequence Column 值大于表中的值,所以数据被替换。

          上一篇
          标记删除
          下一篇
          数据导出