首页 > 其他分享 >doris:自增列

doris:自增列

时间:2025-01-15 12:01:33浏览次数:3  
标签:value 增列 tbl NULL id doris user

在 Doris 中,自增列(Auto Increment Column)是一种自动生成唯一数字值的功能,常用于为每一行数据生成唯一的标识符,如主键。每当插入新记录时,自增列会自动分配一个递增的值,避免了手动指定数字的繁琐操作。使用 Doris 自增列,可以确保数据的唯一性和一致性,简化数据插入过程,减少人为错误,并提高数据管理的效率。这使得自增列成为处理需要唯一标识的场景(如用户 ID 等)时的理想选择。

功能

对于具有自增列的表,Doris处理数据写入的方式如下:

  • 自动填充(列排除): 如果写入的数据不包括自增列,Doris会生成并填充该列的唯一值。

  • 部分指定(列包含)

    • 空值:Doris会用系统生成的唯一值替换写入数据中的空值。
    • 非空值:用户提供的值保持不变。

    重要

    用户提供的非空值可能会破坏自增列的唯一性。

唯一性

Doris保证自增列中生成的值具有表级唯一性。但是:

  • 保证唯一性:这仅适用于系统生成的值。
  • 用户提供的值:Doris不会验证或强制执行用户在自增列中指定的值的唯一性。这可能导致重复条目。

聚集性

Doris生成的自增值通常是密集的,但有一些考虑:

  • 潜在的间隙:由于性能优化,可能会出现间隙。每个后端节点(BE)会预分配一块唯一值以提高效率,这些块在节点之间不重叠。

  • 非时间顺序值:Doris不保证后续写入生成的值大于早期写入的值。

    注意

    自增值不能用于推断写入的时间顺序。

语法

要使用自增列,需要在建表CREATE-TABLE时为对应的列添加AUTO_INCREMENT属性。若要手动指定自增列起始值,可以通过建表时AUTO_INCREMENT(start_value)语句指定,如果未指定,则默认起始值为 1。

示例

  1. 创建一个 Dupliciate 模型表,其中一个 key 列是自增列
CREATE TABLE `demo`.`tbl` (
      `id` BIGINT NOT NULL AUTO_INCREMENT,
      `value` BIGINT NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

  1. 创建一个 Dupliciate 模型表,其中一个 key 列是自增列,并设置起始值为 100
CREATE TABLE `demo`.`tbl` (
      `id` BIGINT NOT NULL AUTO_INCREMENT(100),
      `value` BIGINT NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

  1. 创建一个 Dupliciate 模型表,其中一个 value 列是自增列
CREATE TABLE `demo`.`tbl` (
      `uid` BIGINT NOT NULL,
      `name` BIGINT NOT NULL,
      `id` BIGINT NOT NULL AUTO_INCREMENT,
      `value` BIGINT NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`uid`, `name`)
DISTRIBUTED BY HASH(`uid`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

  1. 创建一个 Unique 模型表,其中一个 key 列是自增列
CREATE TABLE `demo`.`tbl` (
      `id` BIGINT NOT NULL AUTO_INCREMENT,
      `name` varchar(65533) NOT NULL,
      `value` int(11) NOT NULL
) ENGINE=OLAP
UNIQUE KEY(`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

  1. 创建一个 Unique 模型表,其中一个 value 列是自增列
CREATE TABLE `demo`.`tbl` (
      `text` varchar(65533) NOT NULL,
      `id` BIGINT NOT NULL AUTO_INCREMENT,
) ENGINE=OLAP
UNIQUE KEY(`text`)
DISTRIBUTED BY HASH(`text`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

约束和限制

  1. 仅 Duplicate 模型表和 Unique 模型表可以包含自增列。
  2. 一张表最多只能包含一个自增列。
  3. 自增列的类型必须是 BIGINT 类型,且必须为 NOT NULL。
  4. 自增列手动指定的起始值必须大于等于 0。

使用方式

普通导入

以下表为例:

CREATE TABLE `demo`.`tbl` (
    `id` BIGINT NOT NULL AUTO_INCREMENT,
    `name` varchar(65533) NOT NULL,
    `value` int(11) NOT NULL
) ENGINE=OLAP
UNIQUE KEY(`id`)
DISTRIBUTED BY HASH(`id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

使用 insert into 语句导入并且不指定自增列id时,id列会被自动填充生成的值。

mysql> insert into tbl(name, value) values("Bob", 10), ("Alice", 20), ("Jack", 30);
Query OK, 3 rows affected (0.09 sec)
{'label':'label_183babcb84ad4023_a2d6266ab73fb5aa', 'status':'VISIBLE', 'txnId':'7'}

mysql> select * from tbl order by id;
+------+-------+-------+
| id   | name  | value |
+------+-------+-------+
|    1 | Bob   |    10 |
|    2 | Alice |    20 |
|    3 | Jack  |    30 |
+------+-------+-------+
3 rows in set (0.05 sec)

类似地,使用 stream load 导入文件 test.csv 且不指定自增列idid列会被自动填充生成的值。

test.csv:

Tom,40
John,50

curl --location-trusted -u user:passwd -H "columns:name,value" -H "column_separator:," -T ./test.csv http://{host}:{port}/api/{db}/tbl/_stream_load

mysql> select * from tbl order by id;
+------+-------+-------+
| id   | name  | value |
+------+-------+-------+
|    1 | Bob   |    10 |
|    2 | Alice |    20 |
|    3 | Jack  |    30 |
|    4 | Tom   |    40 |
|    5 | John  |    50 |
+------+-------+-------+
5 rows in set (0.04 sec)

使用 insert into 导入时指定自增列id,则该列数据中的 null 值会被生成的值替换。

mysql> insert into tbl(id, name, value) values(null, "Doris", 60), (null, "Nereids", 70);
Query OK, 2 rows affected (0.07 sec)
{'label':'label_9cb0c01db1a0402c_a2b8b44c11ce4703', 'status':'VISIBLE', 'txnId':'10'}

mysql> select * from tbl order by id;
+------+---------+-------+
| id   | name    | value |
+------+---------+-------+
|    1 | Bob     |    10 |
|    2 | Alice   |    20 |
|    3 | Jack    |    30 |
|    4 | Tom     |    40 |
|    5 | John    |    50 |
|    6 | Doris   |    60 |
|    7 | Nereids |    70 |
+------+---------+-------+
7 rows in set (0.04 sec)

部分列更新

在对一张包含自增列的 merge-on-write Unique 表进行部分列更新时,如果自增列是 key 列,由于部分列更新时用户必须显示指定 key 列,部分列更新的目标列必须包含自增列。此时的导入行为和普通的部分列更新相同。

mysql> CREATE TABLE `demo`.`tbl2` (
    ->     `id` BIGINT NOT NULL AUTO_INCREMENT,
    ->     `name` varchar(65533) NOT NULL,
    ->     `value` int(11) NOT NULL DEFAULT "0"
    -> ) ENGINE=OLAP
    -> UNIQUE KEY(`id`)
    -> DISTRIBUTED BY HASH(`id`) BUCKETS 10
    -> PROPERTIES (
    -> "replication_allocation" = "tag.location.default: 3",
    -> "enable_unique_key_merge_on_write" = "true"
    -> );
Query OK, 0 rows affected (0.03 sec)

mysql> insert into tbl2(id, name, value) values(1, "Bob", 10), (2, "Alice", 20), (3, "Jack", 30);
Query OK, 3 rows affected (0.14 sec)
{'label':'label_5538549c866240b6_bce75ef323ac22a0', 'status':'VISIBLE', 'txnId':'1004'}

mysql> select * from tbl2 order by id;
+------+-------+-------+
| id   | name  | value |
+------+-------+-------+
|    1 | Bob   |    10 |
|    2 | Alice |    20 |
|    3 | Jack  |    30 |
+------+-------+-------+
3 rows in set (0.08 sec)

mysql> set enable_unique_key_partial_update=true;
Query OK, 0 rows affected (0.01 sec)

mysql> set enable_insert_strict=false;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tbl2(id, name) values(1, "modified"), (4, "added");
Query OK, 2 rows affected (0.06 sec)
{'label':'label_3e68324cfd87457d_a6166cc0a878cfdc', 'status':'VISIBLE', 'txnId':'1005'}

mysql> select * from tbl2 order by id;
+------+----------+-------+
| id   | name     | value |
+------+----------+-------+
|    1 | modified |    10 |
|    2 | Alice    |    20 |
|    3 | Jack     |    30 |
|    4 | added    |     0 |
+------+----------+-------+
4 rows in set (0.04 sec)

当自增列是非 key 列时,如果用户没有指定自增列的值,其值会从表中原有的数据行中进行补齐。如果用户指定了自增列,则该列数据中的 null 值会被替换为生成出的值,非 null 值则保持不变,然后以部分列更新的语义插入该表。

mysql> CREATE TABLE `demo`.`tbl3` (
    ->     `id` BIGINT NOT NULL,
    ->     `name` varchar(100) NOT NULL,
    ->     `score` BIGINT NOT NULL,
    ->     `aid` BIGINT NOT NULL AUTO_INCREMENT
    -> ) ENGINE=OLAP
    -> UNIQUE KEY(`id`)
    -> DISTRIBUTED BY HASH(`id`) BUCKETS 1
    -> PROPERTIES (
    -> "replication_allocation" = "tag.location.default: 3",
    -> "enable_unique_key_merge_on_write" = "true"
    -> );
Query OK, 0 rows affected (0.16 sec)

mysql> insert into tbl3(id, name, score) values(1, "Doris", 100), (2, "Nereids", 200), (3, "Bob", 300);
Query OK, 3 rows affected (0.28 sec)
{'label':'label_c52b2c246e244dda_9b91ee5e27a31f9b', 'status':'VISIBLE', 'txnId':'2003'}

mysql> select * from tbl3 order by id;
+------+---------+-------+------+
| id   | name    | score | aid  |
+------+---------+-------+------+
|    1 | Doris   |   100 |    0 |
|    2 | Nereids |   200 |    1 |
|    3 | Bob     |   300 |    2 |
+------+---------+-------+------+
3 rows in set (0.13 sec)

mysql> set enable_unique_key_partial_update=true;
Query OK, 0 rows affected (0.00 sec)

mysql> set enable_insert_strict=false;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tbl3(id, score) values(1, 999), (2, 888);
Query OK, 2 rows affected (0.07 sec)
{'label':'label_dfec927d7a4343ca_9f9ade581391de97', 'status':'VISIBLE', 'txnId':'2004'}

mysql> select * from tbl3 order by id;
+------+---------+-------+------+
| id   | name    | score | aid  |
+------+---------+-------+------+
|    1 | Doris   |   999 |    0 |
|    2 | Nereids |   888 |    1 |
|    3 | Bob     |   300 |    2 |
+------+---------+-------+------+
3 rows in set (0.06 sec)

mysql> insert into tbl3(id, aid) values(1, 1000), (3, 500);
Query OK, 2 rows affected (0.07 sec)
{'label':'label_b26012959f714f60_abe23c87a06aa0bf', 'status':'VISIBLE', 'txnId':'2005'}

mysql> select * from tbl3 order by id;
+------+---------+-------+------+
| id   | name    | score | aid  |
+------+---------+-------+------+
|    1 | Doris   |   999 | 1000 |
|    2 | Nereids |   888 |    1 |
|    3 | Bob     |   300 |  500 |
+------+---------+-------+------+
3 rows in set (0.06 sec)

使用场景

字典编码

在用户画像场景中使用 bitmap 做人群分析时需要构建用户字典,每个用户对应一个唯一的整数字典值,聚集的字典值可以获得更好的 bitmap 性能。

以离线 uv,pv 分析场景为例,假设有如下用户行为表存放明细数据:

CREATE TABLE `demo`.`dwd_dup_tbl` (
    `user_id` varchar(50) NOT NULL,
    `dim1` varchar(50) NOT NULL,
    `dim2` varchar(50) NOT NULL,
    `dim3` varchar(50) NOT NULL,
    `dim4` varchar(50) NOT NULL,
    `dim5` varchar(50) NOT NULL,
    `visit_time` DATE NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`user_id`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 32
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

利用自增列创建如下字典表

CREATE TABLE `demo`.`dictionary_tbl` (
    `user_id` varchar(50) NOT NULL,
    `aid` BIGINT NOT NULL AUTO_INCREMENT
) ENGINE=OLAP
UNIQUE KEY(`user_id`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 32
PROPERTIES (
"replication_allocation" = "tag.location.default: 3",
"enable_unique_key_merge_on_write" = "true"
);

将存量数据中的user_id导入字典表,建立user_id到整数值的编码映射

insert into dictionary_tbl(user_id)
select user_id from dwd_dup_tbl group by user_id;

或者使用如下方式仅将增量数据中的user_id导入到字典表

insert into dictionary_tbl(user_id)
select dwd_dup_tbl.user_id from dwd_dup_tbl left join dictionary_tbl
on dwd_dup_tbl.user_id = dictionary_tbl.user_id where dwd_dup_tbl.visit_time > '2023-12-10' and dictionary_tbl.user_id is NULL;

实际场景中也可以使用 flink connector 把数据写入到 doris。

假设dim1dim3dim5是我们关心的统计维度,建立如下聚合表存放聚合结果

CREATE TABLE `demo`.`dws_agg_tbl` (
    `dim1` varchar(50) NOT NULL,
    `dim3` varchar(50) NOT NULL,
    `dim5` varchar(50) NOT NULL,
    `user_id_bitmap` BITMAP BITMAP_UNION NOT NULL,
    `pv` BIGINT SUM NOT NULL 
) ENGINE=OLAP
AGGREGATE KEY(`dim1`,`dim3`,`dim5`)
DISTRIBUTED BY HASH(`dim1`) BUCKETS 32
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

将数据聚合运算后存放至聚合结果表

insert into dws_agg_tbl
select dwd_dup_tbl.dim1, dwd_dup_tbl.dim3, dwd_dup_tbl.dim5, BITMAP_UNION(TO_BITMAP(dictionary_tbl.aid)), COUNT(1)
from dwd_dup_tbl INNER JOIN dictionary_tbl on dwd_dup_tbl.user_id = dictionary_tbl.user_id
group by dwd_dup_tbl.dim1, dwd_dup_tbl.dim3, dwd_dup_tbl.dim5;

用如下语句进行 uv, pv 查询

select dim1, dim3, dim5, bitmap_count(user_id_bitmap) as uv, pv from dws_agg_tbl;

高效分页

在页面展示数据时,往往需要做分页展示。传统的分页通常使用 SQL 中的 limitoffset + order by 进行查询。例如有如下业务表需要进行展示:

CREATE TABLE `demo`.`records_tbl` (
    `user_id` int(11) NOT NULL COMMENT "",
    `name` varchar(26) NOT NULL COMMENT "",
    `address` varchar(41) NOT NULL COMMENT "",
    `city` varchar(11) NOT NULL COMMENT "",
    `nation` varchar(16) NOT NULL COMMENT "",
    `region` varchar(13) NOT NULL COMMENT "",
    `phone` varchar(16) NOT NULL COMMENT "",
    `mktsegment` varchar(11) NOT NULL COMMENT ""
) DUPLICATE KEY (`user_id`, `name`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

假设在分页展示中,每页展示 100 条数据。那么获取第 1 页的数据可以使用如下 sql 进行查询:

select * from records_tbl order by user_id, name limit 100;

获取第 2 页的数据可以使用如下 sql 进行查询:

select * from records_tbl order by user_id, name limit 100 offset 100;

然而,当进行深分页查询时 (offset 很大时),即使实际需要需要的数据行很少,该方法依然会将全部数据读取到内存中进行全量排序后再进行后续处理,这种方法比较低效。可以通过自增列给每行数据一个唯一值,在查询时就可以通过记录之前页面unique_value列的最大值max_value,然后使用 where unique_value > max_value limit rows_per_page 的方式通过提下推谓词提前过滤大量数据,从而更高效地实现分页。

仍然以上述业务表为例,通过在表中添加一个自增列从而赋予每一行一个唯一标识:

CREATE TABLE `demo`.`records_tbl2` (
    `user_id` int(11) NOT NULL COMMENT "",
    `name` varchar(26) NOT NULL COMMENT "",
    `address` varchar(41) NOT NULL COMMENT "",
    `city` varchar(11) NOT NULL COMMENT "",
    `nation` varchar(16) NOT NULL COMMENT "",
    `region` varchar(13) NOT NULL COMMENT "",
    `phone` varchar(16) NOT NULL COMMENT "",
    `mktsegment` varchar(11) NOT NULL COMMENT "",
    `unique_value` BIGINT NOT NULL AUTO_INCREMENT
) DUPLICATE KEY (`user_id`, `name`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 10
PROPERTIES (
"replication_allocation" = "tag.location.default: 3"
);

在分页展示中,每页展示 100 条数据,使用如下方式获取第一页的数据:

select * from records_tbl2 order by unique_value limit 100;

通过程序记录下返回结果中unique_value中的最大值,假设为 99,则可用如下方式查询第 2 页的数据:

select * from records_tbl2 where unique_value > 99 order by unique_value limit 100;

如果要直接查询一个靠后页面的内容,此时不方便直接获取之前页面数据中unique_value的最大值时,例如要直接获取第 101 页的内容,则可以使用如下方式进行查询

select user_id, name, address, city, nation, region, phone, mktsegment
from records_tbl2, (select unique_value as max_value from records_tbl2 order by unique_value limit 1 offset 9999) as previous_data
where records_tbl2.unique_value > previous_data.max_value
order by unique_value limit 100;

标签:value,增列,tbl,NULL,id,doris,user
From: https://blog.csdn.net/qq_36070104/article/details/145157607

相关文章

  • doris:远程存储
    概述​远程存储支持将冷数据放到外部存储(例如对象存储,HDFS)上。注意远程存储的数据只有一个副本,数据可靠性依赖远程存储的数据可靠性,您需要保证远程存储有ec(擦除码)或者多副本技术确保数据可靠性。使用方法​冷数据保存到S3兼容存储​第一步: 创建S3Resource。CREATE......
  • doris&clickhouse&spark的元数据解析
    1.元数据的核心作用-数据目录管理-权限管理-分片信息-版本控制-资源调度2.基本组成部分-表结构定义-分区信息-统计信息-依赖关系-访问控制3.各系统的特点Doris:-FE管理的表定义、分区等-分布式事务相关元数据ClickHouse:-ZK存储的集群......
  • doris:自动分桶
    用户经常设置不合适的bucket,导致各种问题,这里提供一种方式,来自动设置分桶数。当前只对OLAP表生效。警告注意:这个功能在被CCR同步时将会失效。如果这个表是被CCR复制而来的,即PROPERTIES中包含is_being_synced=true时,在showcreatetable中会显示开启状态,但不会实际......
  • docker 安装doris
    下载镜像dockerpullapache/doris:build-env-ldb-toolchain-latest下载安装包https://doris.apache.org/zh-CN/downloadwgethttps://apache-doris-releases.oss-accelerate.aliyuncs.com/apache-doris-2.1.7-bin-x64.tar.gz然后需要下载MySQL,这里提供MySQL的免......
  • Apache Doris 软件部署(2.1.7版本)
    软件介绍:ApacheDoris介绍_rustapachedoris-CSDN博客一、软件依赖环境配置1、检查软硬件环境cat/proc/cpuinfo|grepavx2如果没有返回,则不支持avx2,后续下载包有影响2、设置系统最大打开文件句柄数vi/etc/security/limits.conf添加如下内容*softnofile100000......
  • 用Apache Doris实现实时向量存储与查询
    文章目录概要整体架构流程技术名词解释技术细节小结概要提示:这里可以添加技术概要例如:openAI的GPT大模型的发展历程。整体架构流程提示:这里可以添加技术整体架构例如:在语言模型中,编码器和解码器都是由一个个的Transformer组件拼接在一起形成的。技术......
  • 当Doris学会了“说方言“: 让你的SQL自由转换
    当Doris学会了"说方言":让你的SQL自由转换DorisSQL方言兼容:让数据迁移如丝般顺滑从"方言困境"到"语言大师"数据迁移好比搬家,每个数据工程师都曾面临这样的烦恼:一大堆SQL语句需要改写,就像要把所有家具都重新组装一遍。不同系统的SQL语法就像不同的方言,虽然......
  • Apache SeaTunnel如何实现MongoDB到Doris无缝数据同步?
    如果你需要使用ApacheSeaTunnel将MongoDB数据库的数据同步到Doris,你可以按照以下步骤进行操作。这些步骤基于ApacheSeaTunnel的官方文档和社区提供的最佳实践:一、环境准备下载并安装SeaTunnel:访问SeaTunnel的官方GitHub页面,下载最新稳定版本的SeaTunnel。解压下载的文件......
  • 高性能实时分析型数据库Doris
    ApacheDoris是一个基于MPP的现代化、高性能、支持实时的分析型数据库,以极速易用的特性被业内所熟知。以下是对它的详细介绍:发展历程ApacheDoris最早是诞生于百度广告报表业务的Palo项目,2017年正式对外开源,2018年7月由百度捐赠给Apache基金会进行孵化,2022年6月成功从Apache孵化......
  • 震惊!Doris和Hive竟然能这样玩?数据分析的松弛感拉满
    震惊!Doris和Hive竟然能这样玩?数据分析的松弛感拉满Doris与Hive的完美邂逅Doris-HiveCatalog核心特性多样化的存储支持智能的元数据管理企业级安全特性凌晨三点,办公室里只剩下屏幕的幽光。数据工程师小明正在和两个"大家伙"较劲——Doris和Hive。“导出、清洗、......