Doris使用手册以及与Mysql差异整理

目录

数据类型

Doris数据类型

数值类型

日期类型

字符串类型

半结构类型

聚合类型

[IP 类型](#IP 类型)

[MySQL 到 Doris 类型映射](#MySQL 到 Doris 类型映射)

数据模型

Doris的数据模型

[Aggregate 模型](#Aggregate 模型)

示例一:导入数据聚合

建表

插入数据

查看表

示例二:保留明细数据

示例三:导入数据与已有数据聚合

[Uniq 模型](#Uniq 模型)

建表

插入数据

查询表

使用注意

[Duplicate 模型](#Duplicate 模型)

建表

插入数据

查看表

数据模型的选择建议

与mysql差异

语法

DDL

Create-Table

[Doris 建表语法](#Doris 建表语法)

[与 MySQL 的不同之处](#与 MySQL 的不同之处)

Create-Index

Create-View

Alter-Table/Alter-Index

Drop-Table/Drop-Index

DML

Insert

Update

Delete

Select

[SQL Function](#SQL Function)

事务

显式事务和隐式事务

显式事务

隐式事务

事务操作

开启事务

提交事务

回滚事务

事务写入

[单表多次INSERT INTO VALUES写入](#单表多次INSERT INTO VALUES写入)

[多表多次INSERT INTO SELECT, UPDATE, DELETE写入](#多表多次INSERT INTO SELECT, UPDATE, DELETE写入)

隔离级别

事务中执行失败的语句

常见问题

[与 MySQL差异](#与 MySQL差异)

隔离级别

显式事务

隐式事务

嵌套事务

事务写入

[事务中的 DELETE 和 INSERT 操作](#事务中的 DELETE 和 INSERT 操作)

事务超时

[JDBC 连接](#JDBC 连接)

[Stream Load 2PC](#Stream Load 2PC)

索引

索引分类和原理

点查索引

前缀索引

倒排索引

跳数索引

[ZoneMap 索引](#ZoneMap 索引)

[BloomFilter 索引](#BloomFilter 索引)

[NGram BloomFilter 索引](#NGram BloomFilter 索引)

与MySql差异

索引类型

索引创建

索引使用

索引与数据模型的配合

索引的适用场景

索引的局限性

索引维护


数据类型

Doris数据类型

数值类型

类型名 存储空间(字节) 描述
BOOLEAN 1 布尔值,0 代表 false,1 代表 true。
TINYINT 1 有符号整数,范围 [-128, 127]。
SMALLINT 2 有符号整数,范围 [-32768, 32767]。
INT 4 有符号整数,范围 [-2147483648, 2147483647]
BIGINT 8 有符号整数,范围 [-9223372036854775808, 9223372036854775807]。
LARGEINT 16 有符号整数,范围 [-2^127 + 1 ~ 2^127 - 1]。
FLOAT 4 浮点数,范围 [-3.410^38 ~ 3.410^38]。
DOUBLE 8 浮点数,范围 [-1.7910^308 ~ 1.7910^308]。
DECIMAL 4/8/16 高精度定点数,格式:DECIMAL(M[,D])。其中,M 代表一共有多少个有效数字(precision),D 代表小数位有多少数字(scale)。有效数字 M 的范围是 [1, 38],小数位数字数量 D 的范围是 [0, precision]。0 < precision <= 9 的场合,占用 4 字节。9 < precision <= 18 的场合,占用 8 字节。16 < precision <= 38 的场合,占用 16 字节。

日期类型

类型名 存储空间(字节) 描述
DATE 16 日期类型,目前的取值范围是 ['0000-01-01', '9999-12-31'],默认的打印形式是 'yyyy-MM-dd'。
DATETIME 16 日期时间类型,格式:DATETIME([P])。可选参数 P 表示时间精度,取值范围是 [0, 6],即最多支持 6 位小数(微秒)。不设置时为 0。 取值范围是 ['0000-01-01 00:00:00[.000000]', '9999-12-31 23:59:59[.999999]']。打印的形式是 'yyyy-MM-dd HH:mm:ss.SSSSSS'。

字符串类型

类型名 存储空间(字节) 描述
CHAR M 定长字符串,M 代表的是定长字符串的字节长度。M 的范围是 1-255。
VARCHAR 不定长 变长字符串,M 代表的是变长字符串的字节长度。M 的范围是 1-65533。变长字符串是以 UTF-8 编码存储的,因此通常英文字符占 1 个字节,中文字符占 3 个字节。
STRING 不定长 变长字符串,默认支持 1048576 字节(1MB),可调大到 2147483643 字节(2GB)。可通过 BE 配置 string_type_length_soft_limit_bytes 调整。String 类型只能用在 Value 列,不能用在 Key 列和分区分桶列。

半结构类型

类型名 存储空间(字节) 描述
ARRAY 不定长 由 T 类型元素组成的数组,不能作为 Key 列使用。目前支持在 Duplicate 和 Unique 模型的表中使用。
MAP 不定长 由 K, V 类型元素组成的 map,不能作为 Key 列使用。目前支持在 Duplicate 和 Unique 模型的表中使用。
STRUCT 不定长 由多个 Field 组成的结构体,也可被理解为多个列的集合。不能作为 Key 使用,目前 STRUCT 仅支持在 Duplicate 模型的表中使用。一个 Struct 中的 Field 的名字和数量固定,总是为 Nullable。
JSON 不定长 二进制 JSON 类型,采用二进制 JSON 格式存储,通过 JSON 函数访问 JSON 内部字段。长度限制和配置方式与 String 相同
VARIANT 不定长 动态可变数据类型,专为半结构化数据如 JSON 设计,可以存入任意 JSON,自动将 JSON 中的字段拆分成子列存储,提升存储效率和查询分析性能。长度限制和配置方式与 String 相同。Variant 类型只能用在 Value 列,不能用在 Key 列和分区分桶列。

聚合类型

类型名 存储空间(字节) 描述
HLL 不定长 HLL 是模糊去重,在数据量大的情况性能优于 Count Distinct。HLL 的误差通常在 1% 左右,有时会达到 2%。HLL 不能作为 Key 列使用,建表时配合聚合类型为 HLL_UNION。用户不需要指定长度和默认值。长度根据数据的聚合程度系统内控制。HLL 列只能通过配套的 hll_union_agg、hll_raw_agg、hll_cardinality、hll_hash 进行查询或使用。
BITMAP 不定长 Bitmap 类型的列可以在 Aggregate 表、Unique 表或 Duplicate 表中使用。在 Unique 表或 Duplicate 表中使用时,其必须作为非 Key 列使用。在 Aggregate 表中使用时,其必须作为非 Key 列使用,且建表时配合的聚合类型为 BITMAP_UNION。用户不需要指定长度和默认值。长度根据数据的聚合程度系统内控制。BITMAP 列只能通过配套的 bitmap_union_count、bitmap_union、bitmap_hash、bitmap_hash64 等函数进行查询或使用。
QUANTILE_STATE 不定长 QUANTILE_STATE 是一种计算分位数近似值的类型,在导入时会对相同的 Key,不同 Value 进行预聚合,当 value 数量不超过 2048 时采用明细记录所有数据,当 Value 数量大于 2048 时采用 TDigest 算法,对数据进行聚合(聚类)保存聚类后的质心点。QUANTILE_STATE 不能作为 Key 列使用,建表时配合聚合类型为 QUANTILE_UNION。用户不需要指定长度和默认值。长度根据数据的聚合程度系统内控制。QUANTILE_STATE 列只能通过配套的 QUANTILE_PERCENT、QUANTILE_UNION、TO_QUANTILE_STATE 等函数进行查询或使用。
AGG_STATE 不定长 聚合函数,只能配合 state/merge/union 函数组合器使用。AGG_STATE 不能作为 Key 列使用,建表时需要同时声明聚合函数的签名。用户不需要指定长度和默认值。实际存储的数据大小与函数实现有关。

IP 类型

类型名 存储空间(字节) 描述
IPv4 4 字节 以 4 字节二进制存储 IPv4 地址,配合 ipv4_* 系列函数使用。
IPv6 16 字节 以 16 字节二进制存储 IPv6 地址,配合 ipv6_* 系列函数使用。

也可通过SHOW DATA TYPES;语句查看 Apache Doris 支持的所有数据类型。

MySQL 到 Doris 类型映射

MYSQL Type Doris Type Comment
BOOLEAN TINYINT
TINYINT TINYINT
SMALLINT SMALLINT
MEDIUMINT INT
INT INT
BIGINT BIGINT
UNSIGNED TINYINT SMALLINT
UNSIGNED MEDIUMINT INT
UNSIGNED INT BIGINT
UNSIGNED BIGINT LARGEINT
FLOAT FLOAT
DOUBLE DOUBLE
DECIMAL DECIMAL
UNSIGNED DECIMAL(p,s) DECIMAL(p+1,s) / STRING
DATE DATE
TIMESTAMP DATETIME
DATETIME DATETIME
YEAR SMALLINT
TIME STRING
CHAR CHAR
VARCHAR VARCHAR
JSON STRING
SET STRING
ENUM STRING
BIT BOOLEAN/STRING
TINYTEXT,TEXT,MEDIUMTEXT,LONGTEXT STRING
BLOB,MEDIUMBLOB,LONGBLOB,TINYBLOB STRING
BINARY,VARBINARY STRING

数据模型

Doris的数据模型

Doris 的数据模型主要分为3类:Aggregate、Uniq、Duplicate

Aggregate 模型

表中的列按照是否设置了AggregationType,分为 Key(维度列)和 Value(指标列)。没有设置AggregationType的称为 Key,设置了AggregationType的称为Value。

当我们导入数据时,对于Key列相同的行会聚合成一行,而Value列会按照设置的 AggregationType进行聚合。AggregationType目前有以下四种聚合方式:

  • SUM:求和,多行的Value进行累加。

  • REPLACE:替代,下一批数据中的Value会替换之前导入过的行中的 Value。

    REPLACE_IF_NOT_NULL :当遇到null值则不更新。

  • MAX:保留最大值。

  • MIN:保留最小值。

数据的聚合,在 Doris 中有如下三个阶段发生:

  1. 每一批次数据导入的 ETL 阶段。该阶段会在每一批次导入的数据内部进行聚合。

  2. 底层 BE 进行数据 Compaction 的阶段。该阶段,BE 会对已导入的不同批次的数据进行进一步的聚合。

  3. 数据查询阶段。在数据查询时,对于查询涉及到的数据,会进行对应的聚合。

    数据在不同时间,可能聚合的程度不一致。比如一批数据刚导入时,可能还未与之前已存在的数据进行聚合。但是对于用户而言,用户只能查询到聚合后的数据。即不同的聚合程度对于用户查询而言是透明的。用户需始终认为数据以最终的完成的聚合程度存在,而不应假设某些聚合还未发生。(可参阅聚合模型的局限性一节获得更多详情。)

示例一:导入数据聚合
建表
sql 复制代码
CREATE TABLE IF NOT EXISTS test_db.example_site_visit

(

    `user_id` LARGEINT NOT NULL COMMENT "用户id",

    `date` DATE NOT NULL COMMENT "数据灌入日期时间",

    `city` VARCHAR(20) COMMENT "用户所在城市",

    `age` SMALLINT COMMENT "用户年龄",

    `sex` TINYINT COMMENT "用户性别",

`last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",

    `last_visit_date_not_null` DATETIME REPLACE_IF_NOT_NULL DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",



    `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",

    `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",

    `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间"

)

AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;
插入数据
sql 复制代码
insert into test_db.example_site_visit values\

(10000,'2017-10-01','北京',20,0,'2017-10-01 06:00:00','2017-10-01 06:00:00',20,10,10),\

(10000,'2017-10-01','北京',20,0,'2017-10-01 07:00:00','2017-10-01 07:00:00',15,2,2),\

(10001,'2017-10-01','北京',30,1,'2017-10-01 17:05:45','2017-10-01 07:00:00',2,22,22),\

(10002,'2017-10-02','上海',20,1,'2017-10-02 12:59:12',null,200,5,5),\

(10003,'2017-10-02','广州',32,0,'2017-10-02 11:20:00','2017-10-02 11:20:00',30,11,11),\

(10004,'2017-10-01','深圳',35,0,'2017-10-01 10:00:15','2017-10-01 10:00:15',100,3,3),\

(10004,'2017-10-03','深圳',35,0,'2017-10-03 10:20:22','2017-10-03 10:20:22',11,6,6);

注意:Insert into 单条数据这种操作在Doris里只能演示不能在生产使用,会引发写阻塞。
3.

查看表
sql 复制代码
select * from test_db.example_site_visit;

可以看到,用户 10000 只剩下了一行聚合后的数据。而其余用户的数据和原始数据保持一致。经过聚合,Doris 中最终只会存储聚合后的数据。换句话说,即明细数据会丢失,用户不能够再查询到聚合前的明细数据了。

示例二:保留明细数据
  1. 建表

    sql 复制代码
    CREATE TABLE IF NOT EXISTS test_db.example_site_visit2
    
    (
    
        `user_id` LARGEINT NOT NULL COMMENT "用户id",
    
        `date` DATE NOT NULL COMMENT "数据灌入日期时间",
    
        `timestamp` DATETIME COMMENT "数据灌入时间,精确到秒",
    
        `city` VARCHAR(20) COMMENT "用户所在城市",
    
        `age` SMALLINT COMMENT "用户年龄",
    
        `sex` TINYINT COMMENT "用户性别",
    
        `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",
    
        `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
    
        `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
    
        `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间"
    
    )
    
    AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
    
    DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;
  2. 插入数据

    sql 复制代码
    insert into test_db.example_site_visit2 values(10000,'2017-10-01','2017-10-01 08:00:05','北京',20,0,'2017-10-01 06:00:00',20,10,10),\
    
    (10000,'2017-10-01','2017-10-01 09:00:05','北京',20,0,'2017-10-01 07:00:00',15,2,2),\
    
    (10001,'2017-10-01','2017-10-01 18:12:10','北京',30,1,'2017-10-01 17:05:45',2,22,22),\
    
    (10002,'2017-10-02','2017-10-02 13:10:00','上海',20,1,'2017-10-02 12:59:12',200,5,5),\
    
    (10003,'2017-10-02','2017-10-02 13:15:00','广州',32,0,'2017-10-02 11:20:00',30,11,11),\
    
    (10004,'2017-10-01','2017-10-01 12:12:48','深圳',35,0,'2017-10-01 10:00:15',100,3,3),\
    
    (10004,'2017-10-03','2017-10-03 12:38:20','深圳',35,0,'2017-10-03 10:20:22',11,6,6);
  3. 查看表

    sql 复制代码
    select * from test_db.example_site_visit2;

    存储的数据,和导入数据完全一样,没有发生任何聚合。这是因为,这批数据中,因为加入了 timestamp 列,所有行的 Key 都不完全相同。也就是说,只要保证导入的数据中,每一行的 Key 都不完全相同,那么即使在聚合模型下,Doris 也可以保存完整的明细数据。

示例三:导入数据与已有数据聚合
  1. 往实例一中继续插入数据

    sql 复制代码
    insert into test_db.example_site_visit values(10004,'2017-10-03','深圳',35,0,'2017-10-03 11:22:00',null,44,19,19),\
    
    (10005,'2017-10-03','长沙',29,1,'2017-10-03 18:11:02','2017-10-03 18:11:02',3,1,1);
  2. 查看表

    sql 复制代码
    select * from test_db.example_site_visit;

    可以看到,用户 10004 的已有数据和新导入的数据发生了聚合。同时新增了 10005 用户的数据。

Uniq 模型

在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此,我们引入了 Uniq 的数据模型。该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式。

主键模型提供了两种实现方式:

  • 读时合并 (merge-on-read)。在读时合并实现中,用户在进行数据写入时不会触发任何数据去重相关的操作,所有数据去重的操作都在查询或者 compaction 时进行。因此,读时合并的写入性能较好,查询性能较差,同时内存消耗也较高。

读时合并的建表语句如下:

sql 复制代码
CREATE TABLE IF NOT EXISTS example_tbl_unique

(

`user_id` LARGEINT NOT NULL COMMENT "用户id",

`username` VARCHAR(50) NOT NULL COMMENT "用户昵称",

`city` VARCHAR(20) COMMENT "用户所在城市",

`age` SMALLINT COMMENT "用户年龄",

`sex` TINYINT COMMENT "用户性别",

`phone` LARGEINT COMMENT "用户电话",

`address` VARCHAR(500) COMMENT "用户地址",

`register_time` DATETIME COMMENT "用户注册时间"

)

UNIQUE KEY(`user_id`, `username`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 1

PROPERTIES (

"replication_allocation" = "tag.location.default: 1"
  • 写时合并 (merge-on-write)。在 1.2 版本中,我们引入了写时合并实现,该实现会在数据写入阶段完成所有数据去重的工作,因此能够提供非常好的查询性能。自 2.0 版本起,写时合并已经非常成熟稳定,由于其优秀的查询性能,我们推荐大部分用户选择该实现。自 2.1 版本,写时合并成为 Unique 模型的默认实现。

写时合并建表语句为:

sql 复制代码
CREATE TABLE IF NOT EXISTS example_tbl_unique_merge_on_write

(

`user_id` LARGEINT NOT NULL COMMENT "用户id",

`username` VARCHAR(50) NOT NULL COMMENT "用户昵称",

`city` VARCHAR(20) COMMENT "用户所在城市",

`age` SMALLINT COMMENT "用户年龄",

`sex` TINYINT COMMENT "用户性别",

`phone` LARGEINT COMMENT "用户电话",

`address` VARCHAR(500) COMMENT "用户地址",

`register_time` DATETIME COMMENT "用户注册时间"

)

UNIQUE KEY(`user_id`, `username`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 1

PROPERTIES (

"replication_allocation" = "tag.location.default: 1",

"enable_unique_key_merge_on_write" = "true"

);

用户需要在建表时添加下面的 property 来开启写时合并。

建表
sql 复制代码
CREATE TABLE IF NOT EXISTS test_db.user

(

    `user_id` LARGEINT NOT NULL COMMENT "用户id",

    `username` VARCHAR(50) NOT NULL COMMENT "用户昵称",

    `city` VARCHAR(20) COMMENT "用户所在城市",

    `age` SMALLINT COMMENT "用户年龄",

    `sex` TINYINT COMMENT "用户性别",

    `phone` LARGEINT COMMENT "用户电话",

    `address` VARCHAR(500) COMMENT "用户地址",

    `register_time` DATETIME COMMENT "用户注册时间"

)

UNIQUE KEY(`user_id`, `username`)

DISTRIBUTED BY HASH(`user_id`) BUCKETS 10;
插入数据
sql 复制代码
insert into test_db.user values\

(10000,'wuyanzu','北京',18,0,12345678910,'北京朝阳区','2017-10-01 07:00:00'),\

(10000,'wuyanzu','北京',19,0,12345678910,'北京朝阳区','2017-10-01 07:00:00'),\

(10000,'zhangsan','北京',20,0,12345678910,'北京海淀区','2017-11-15 06:10:20');
查询表
sql 复制代码
select * from test_db.user;

Uniq 模型完全可以用聚合模型中的 REPLACE 方式替代。其内部的实现方式和数据存储方式也完全一样。

Unique 模型默认的更新语意为整行``UPSERT``,即 UPDATE OR INSERT,该行数据的 key 如果存在,则进行更新,如果不存在,则进行新数据插入。在整行``UPSERT``语意下,即使用户使用 insert into 指定部分列进行写入,Doris 也会在 Planner 中将未提供的列使用 NULL 值或者默认值进行填充。

部分列更新。如果用户希望更新部分字段,需要使用写时合并实现,并通过特定的参数来开启部分列更新的支持。请查阅数据操作/数据更新部分。

使用注意

  • Unique 表的实现方式只能在建表时确定,无法通过 schema change 进行修改。

  • 旧的 Merge-on-Read 的实现无法无缝升级到 Merge-on-Write 的实现(数据组织方式完全不同),如果需要改为使用写时合并的实现版本,需要手动执行 ``insert into unique-mow-table select * from source table`` 来重新导入。

  • 整行更新:Unique 模型默认的更新语意为整行 ``UPSERT``,即 UPDATE OR INSERT,该行数据的 key 如果存在,则进行更新,如果不存在,则进行新数据插入。在整行 ``UPSERT`` 语意下,即使用户使用 insert into 指定部分列进行写入,Doris 也会在 Planner 中将未提供的列使用 NULL 值或者默认值进行填充

  • 部分列更新。如果用户希望更新部分字段,需要使用写时合并(默认模式)实现,并通过特定的参数来开启部分列更新的支持。请查阅文档部分列更新获取相关使用建议。

Duplicate 模型

在某些多维分析场景下,数据既没有主键,也没有聚合需求。Duplicate 数据模型可以满足这类需求。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。

建表
sql 复制代码
CREATE TABLE IF NOT EXISTS test_db.example_log

(

    `timestamp` DATETIME NOT NULL COMMENT "日志时间",

    `type` INT NOT NULL COMMENT "日志类型",

    `error_code` INT COMMENT "错误码",

    `error_msg` VARCHAR(1024) COMMENT "错误详细信息",

    `op_id` BIGINT COMMENT "负责人id",

    `op_time` DATETIME COMMENT "处理时间"

)

DUPLICATE KEY(`timestamp`, `type`)

DISTRIBUTED BY HASH(`timestamp`) BUCKETS 10;
插入数据
sql 复制代码
insert into test_db.example_log values\

('2017-10-01 08:00:05',1,404,'not found page', 101, '2017-10-01 08:00:05'),\

('2017-10-01 08:00:05',1,404,'not found page', 101, '2017-10-01 08:00:05'),\

('2017-10-01 08:00:05',2,404,'not found page', 101, '2017-10-01 08:00:06'),\

('2017-10-01 08:00:06',2,404,'not found page', 101, '2017-10-01 08:00:07');
查看表
sql 复制代码
select * from test_db.example_log;

数据模型的选择建议

因为数据模型在建表时就已经确定,且无法修改。所以,选择一个合适的数据模型非常重要。

  1. Aggregate模型可以通过预聚合,极大地降低聚合查询时所需扫描的数据量和查询的计算量,非常适合有固定模式的报表类查询场景。但是该模型对count(*) 查询很不友好。同时因为固定了Value列上的聚合方式,在进行其他类型的聚合查询时,需要考虑语意正确性。

  2. Uniq模型针对需要唯一主键约束的场景,可以保证主键唯一性约束。但是无法利用 ROLLUP 等预聚合带来的查询优势(因为本质是REPLACE,没有SUM这种聚合方式)。

  3. Duplicate适合任意维度的Ad-hoc查询。虽然同样无法利用预聚合的特性,但是不受聚合模型的约束,可以发挥列存模型的优势(只读取相关列,而不需要读取所有Key列)

与mysql差异

Doris 支持明细模型(Duplicate Key Model)、聚合模型(Aggregate Key Model)和唯一键模型(Unique Key Model),这些模型针对不同的场景做了优化。
MySQL 使用单一的关系型数据模型可以说是没有数据模型概念。

语法

DDL

Create-Table

Doris 建表语法
sql 复制代码
CREATE TABLE [IF NOT EXISTS] [database.]table

(

column_definition_list

[, index_definition_list]

)

[engine_type]

[keys_type]

[table_comment]

[partition_info]

distribution_desc

[rollup_list]

[properties]

[extra_properties]
与 MySQL 的不同之处
  • column_definition_list

    • 字段列表定义,基本语法与 MySQL 类似,会多出一个聚合类型的操作

    • 聚合类型的操作,主要支持数据模型为 AGGREGATE,Duplicate

    • MySQL 可以在建表定义字段列表的时候,还可以在字段后面加上 Index 等约束,例如 primary key,unique key 等,但是 Doris 是通过定义数据模型来约束和计算的。

  • index_definition_list

    • 索引列表定义,基本语法与 MySQL 类似,支持位图索引、倒排索引和 N-Gram 索引,但是布隆过滤器索引是通过属性设置。

    • 而 MySQL 支持的 index 有 B+Tree,Hash。

  • engine_type

    • 表引擎类型,可选

    • 目前支持的表引擎主要是 olap 这种原生引擎。

    • MySQL 支持的存储引擎有:Innodb,MyISAM 等

  • keys_type

    • 数据模型,可选

    • 支持的类型

      • DUPLICATE KEY(默认):其后指定的列为排序列。

      • AGGREGATE KEY:其后指定的列为维度列。

      • UNIQUE KEY:其后指定的列为主键列。

    • MySQL 则没有数据模型的概念。

  • table_comment

    • 表注释
  • partition_info

    • 分区算法,可选

    • 支持的分区算法

      • LESS THAN:仅定义分区上界。下界由上一个分区的上界决定。

      • FIXED RANGE:定义分区的左闭右开区间。

      • MULTI RANGE:批量创建 RANGE 分区,定义分区的左闭右开区间,设定时间单位和步长,时间单位支持年、月、日、周和小时。

      • MULTI RANGE:批量创建数字类型的 RANGE 分区,定义分区的左闭右开区间,设定步长。

    • MySQL 支持的算法:Hash,Range,List,并且还支持子分区,子分区支持的算法只有 Hash。

  • distribution_desc

    • 分桶算法,必选

    • 分桶算法

      • Hash 分桶语法:DISTRIBUTED BY HASH (k1[,k2 ...]) [BUCKETS num|auto] 说明:使用指定的 key 列进行哈希分桶。

      • Random 分桶语法:DISTRIBUTED BY RANDOM [BUCKETS num|auto] 说明:使用随机数进行分桶。

    • MySQL 没有分桶算法

  • rollup_list

    • 建表的同时可以创建多个物化视图,可选

    • rollup_name (col1[, col2, ...]) [DUPLICATE KEY(col1[, col2, ...])][PROPERTIES("key" = "value")]

    • MySQL 不支持

  • properties:

    • 表属性

    • 表属性与 MySQL 的表属性不一致,定义表属性的语法也与 MySQL 不一致

Create-Index

sql 复制代码
CREATE INDEX [IF NOT EXISTS] index_name ON table_name (column [, ...],) [USING BITMAP];
  • 目前支持:位图索引、倒排索引和 N-Gram 索引,布隆过滤器索引(单独的语法设置)

  • MySQL 支持的索引算法有:B+Tree,Hash

Create-View

sql 复制代码
CREATE VIEW [IF NOT EXISTS]

[db_name.]view_name

(column1[ COMMENT "col comment"][, column2, ...])

AS query_stmt



CREATE MATERIALIZED VIEW (IF NOT EXISTS)? mvName=multipartIdentifier

(LEFT_PAREN cols=simpleColumnDefs RIGHT_PAREN)? buildMode?

(REFRESH refreshMethod? refreshTrigger?)?

(KEY keys=identifierList)?

(COMMENT STRING_LITERAL)?

(PARTITION BY LEFT_PAREN partitionKey = identifier RIGHT_PAREN)?

(DISTRIBUTED BY (HASH hashKeys=identifierList | RANDOM) (BUCKETS (INTEGER_VALUE | AUTO))?)?

propertyClause?

AS query
  • 基本语法与 MySQL 一致

  • Doris 支持两种物化视图,同步物化视图和异步物化视图(从 v2.1 开始支持异步物化视图功能)。Doris 的异步物化视图更加强大。

  • MySQL 仅支持异步物化视图

Alter-Table/Alter-Index

Doris Alter 的语法与 MySQL 的基本一致。

Drop-Table/Drop-Index

Doris Drop 的语法与 MySQL 的基本一致

DML

Insert

sql 复制代码
INSERT INTO table_name

[ PARTITION (p1, ...) ]

[ WITH LABEL label]

[ (column [, ...]) ]

[ [ hint [, ...] ] ]

{ VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }

Doris Insert 语法与 MySQL 的基本一致。

Update

sql 复制代码
UPDATE target_table [table_alias]

SET assignment_list

WHERE condition



assignment_list:

assignment [, assignment] ...



assignment:

col_name = value



value:

{expr | DEFAULT}

Doris Update 语法与 MySQL 基本一致,但需要注意的是必须加上 where 条件。

Delete

sql 复制代码
DELETE FROM table_name [table_alias]

[PARTITION partition_name | PARTITIONS (partition_name [, partition_name])]

WHERE column_name op { value | value_list } [ AND column_name op { value | value_list } ...];

Doris 该语法只能指定过滤谓词

sql 复制代码
DELETE FROM table_name [table_alias]

[PARTITION partition_name | PARTITIONS (partition_name [, partition_name])]

[USING additional_tables]

WHERE condition

Doris 该语法只能在 UNIQUE KEY 模型表上使用。

Doris Delete 语法与 MySQL 基本一致。但是由于 Doris 是一个分析数据库,所以删除不能过于频繁。

Select

sql 复制代码
SELECT

[hint_statement, ...]

[ALL | DISTINCT | DISTINCTROW | ALL EXCEPT ( col_name1 [, col_name2, col_name3, ...] )]

select_expr [, select_expr ...]

[FROM table_references

[PARTITION partition_list]

[TABLET tabletid_list]

[TABLESAMPLE sample_value [ROWS | PERCENT]

[REPEATABLE pos_seek]]

[WHERE where_condition]

[GROUP BY [GROUPING SETS | ROLLUP | CUBE] {col_name | expr | position}]

[HAVING where_condition]

[ORDER BY {col_name | expr | position}

[ASC | DESC], ...]

[LIMIT {[offset,] row_count | row_count OFFSET offset}]

[INTO OUTFILE 'file_name']

Doris Select 语法与 MySQL 基本一致

SQL Function

Doris Function 基本覆盖绝大部分 MySQL Function。

事务

事务是指一个操作,包含一个或多个SQL语句,这些语句的执行要么完全成功,要么完全失败,是一个不可分割的工作单位。

显式事务和隐式事务

显式事务

显式事务需要用户主动的开启,提交或回滚事务。 在 Doris 中,提供了 2 种显式事务:

  1. 本文中介绍的事务写方式,即:

    sql 复制代码
    BEGIN;
    
    [INSERT, UPDATE, DELETE statement]
    
    COMMIT; / ROLLBACK;
  2. Stream Load 2PC

隐式事务

隐式事务是指用户在所执行的一条或多条SQL语句的前后,没有显式添加开启事务和提交事务的语句。

在 Doris 中,除Group Commit外,每个导入语句在开始执行时都会开启一个事务,并且在该语句执行完成之后,自动提交该事务;或执行失败后,自动回滚该事务。更多详细信息请参考: 导入事务与原子性

事务操作

开启事务

sql 复制代码
BEGIN;

BEGIN WITH LABEL {user_label};

如果执行该语句时,当前 Session 正处于一个事务的中间过程,那么 Doris 会忽略该语句,也可以理解为事务是不能嵌套的。

提交事务

sql 复制代码
COMMIT;

用于提交在当前事务中进行的所有修改。

回滚事务

sql 复制代码
ROLLBACK;

用于撤销当前事务的所有修改。

事务是 Session 级别的,如果 Session 中止或关闭,也会自动回滚该事务。

事务写入

目前 Doris 中支持 2 种方式的事务写入。

单表多次``INSERT INTO VALUES``写入

假如表的结构为:

sql 复制代码
CREATE TABLE `dt` (

`id` INT(11) NOT NULL,

`name` VARCHAR(50) NULL,

`score` INT(11) NULL

) ENGINE=OLAP

UNIQUE KEY(`id`)

DISTRIBUTED BY HASH(`id`) BUCKETS 1

PROPERTIES (

"replication_num" = "1"

);

写入:

sql 复制代码
mysql> BEGIN;

Query OK, 0 rows affected (0.01 sec)

{'label':'txn_insert_b55db21aad7451b-b5b6c339704920c5', 'status':'PREPARE', 'txnId':''}



mysql> INSERT INTO dt (id, name, score) VALUES (1, "Emily", 25), (2, "Benjamin", 35), (3, "Olivia", 28), (4, "Alexander", 60), (5, "Ava", 17);

Query OK, 5 rows affected (0.08 sec)

{'label':'txn_insert_b55db21aad7451b-b5b6c339704920c5', 'status':'PREPARE', 'txnId':'10013'}



mysql> INSERT INTO dt VALUES (6, "William", 69), (7, "Sophia", 32), (8, "James", 64), (9, "Emma", 37), (10, "Liam", 64);

Query OK, 5 rows affected (0.00 sec)

{'label':'txn_insert_b55db21aad7451b-b5b6c339704920c5', 'status':'PREPARE', 'txnId':'10013'}



mysql> COMMIT;

Query OK, 0 rows affected (1.02 sec)

{'label':'txn_insert_b55db21aad7451b-b5b6c339704920c5', 'status':'VISIBLE', 'txnId':'10013'}

这种写入方式不仅可以实现写入的原子性,而且在 Doris 中,能提升 ``INSERT INTO VALUES`` 的写入性能。

如果用户同时开启了 ``Group Commit`` 和事务写,事务写生效。

也可以参考 Insert Into获取更多信息。

多表多次``INSERT INTO SELECT``, ``UPDATE``, ``DELETE``写入

假设有``dt1``, ``dt2``, ``dt3`` 3 张表,表结构同上,表中数据为:

sql 复制代码
mysql> SELECT * FROM dt1;

+------+-----------+-------+

| id | name | score |

+------+-----------+-------+

| 1 | Emily | 25 |

| 2 | Benjamin | 35 |

| 3 | Olivia | 28 |

| 4 | Alexander | 60 |

| 5 | Ava | 17 |

+------+-----------+-------+

5 rows in set (0.04 sec)



mysql> SELECT * FROM dt2;

+------+---------+-------+

| id | name | score |

+------+---------+-------+

| 6 | William | 69 |

| 7 | Sophia | 32 |

| 8 | James | 64 |

| 9 | Emma | 37 |

| 10 | Liam | 64 |

+------+---------+-------+

5 rows in set (0.03 sec)



mysql> SELECT * FROM dt3;

Empty set (0.03 sec)

做事务写入,把``dt1``和``dt2``的数据写入到``dt3``中,同时,对``dt1``表中的分数进行更新,``dt2``表中的数据进行删除:

sql 复制代码
mysql> BEGIN;

Query OK, 0 rows affected (0.00 sec)

{'label':'txn_insert_442a6311f6c541ae-b57d7f00fa5db028', 'status':'PREPARE', 'txnId':''}



# 导入任务的状态是 PREPARE

mysql> INSERT INTO dt3 SELECT * FROM dt1;

Query OK, 5 rows affected (0.07 sec)

{'label':'txn_insert_442a6311f6c541ae-b57d7f00fa5db028', 'status':'PREPARE', 'txnId':'11024'}



mysql> INSERT INTO dt3 SELECT * FROM dt2;

Query OK, 5 rows affected (0.08 sec)

{'label':'txn_insert_442a6311f6c541ae-b57d7f00fa5db028', 'status':'PREPARE', 'txnId':'11025'}



mysql> UPDATE dt1 SET score = score + 10 WHERE id >= 4;

Query OK, 2 rows affected (0.07 sec)

{'label':'txn_insert_442a6311f6c541ae-b57d7f00fa5db028', 'status':'PREPARE', 'txnId':'11026'}



mysql> DELETE FROM dt2 WHERE id >= 9;

Query OK, 0 rows affected (0.01 sec)

{'label':'txn_insert_442a6311f6c541ae-b57d7f00fa5db028', 'status':'PREPARE', 'txnId':'11027'}



mysql> COMMIT;

Query OK, 0 rows affected (0.03 sec)

{'label':'txn_insert_442a6311f6c541ae-b57d7f00fa5db028', 'status':'VISIBLE', 'txnId':'11024'}

查询数据:

sql 复制代码
# id >= 4 的分数加 10

mysql> SELECT * FROM dt1;

+------+-----------+-------+

| id | name | score |

+------+-----------+-------+

| 1 | Emily | 25 |

| 2 | Benjamin | 35 |

| 3 | Olivia | 28 |

| 4 | Alexander | 70 |

| 5 | Ava | 27 |

+------+-----------+-------+

5 rows in set (0.01 sec)



# id >= 9 的数据被删除

mysql> SELECT * FROM dt2;

+------+---------+-------+

| id | name | score |

+------+---------+-------+

| 6 | William | 69 |

| 7 | Sophia | 32 |

| 8 | James | 64 |

+------+---------+-------+

3 rows in set (0.02 sec)



# dt1 和 dt2 中已提交的数据被写入到 dt3 中

mysql> SELECT * FROM dt3;

+------+-----------+-------+

| id | name | score |

+------+-----------+-------+

| 1 | Emily | 25 |

| 2 | Benjamin | 35 |

| 3 | Olivia | 28 |

| 4 | Alexander | 60 |

| 5 | Ava | 17 |

| 6 | William | 69 |

| 7 | Sophia | 32 |

| 8 | James | 64 |

| 9 | Emma | 37 |

| 10 | Liam | 64 |

+------+-----------+-------+

10 rows in set (0.01 sec)
隔离级别

目前 Doris 事务写提供的隔离级别为 ``READ COMMITTED``。需要注意以下两点:

  • 事务中的多个语句,每个语句会读取到本语句开始执行时已提交的数据,如:

    sql 复制代码
    timestamp | ------------ Session 1 ------------ | ------------ Session 2 ------------
    
    t1 | BEGIN; |
    
    t2 | # read n rows from dt1 table |
    
    | INSERT INTO dt3 SELECT * FROM dt1; |
    
    t3 | | # write 2 rows to dt1 table
    
    | | INSERT INTO dt1 VALUES(...), (...);
    
    t4 | # read n + 2 rows from dt1 table |
    
    | INSERT INTO dt3 SELECT * FROM dt1; |
    
    t5 | COMMIT; |
  • 事务中的多个语句,每个语句不能读到本事务内其它语句做出的修改,如:

    假如事务开启前,表 ``dt1`` 有 5 行,表 ``dt2`` 有 5 行,表 ``dt3`` 为空,执行以下语句:

    sql 复制代码
    BEGIN;
    
    # dt2 中写入 5 行,事务提交后共 10 行
    
    INSERT INTO dt2 SELECT * FROM dt1;
    
    # dt3 中写入 5 行,不能读出上一步中 dt2 中新写入的数据
    
    INSERT INTO dt3 SELECT * FROM dt2;
    
    COMMIT;

    具体的例子为:

    sql 复制代码
    # 建表并写入数据
    
    CREATE TABLE `dt1` (
    
    `id` INT(11) NOT NULL,
    
    `name` VARCHAR(50) NULL,
    
    `score` INT(11) NULL
    
    ) ENGINE=OLAP
    
    DUPLICATE KEY(`id`)
    
    DISTRIBUTED BY HASH(`id`) BUCKETS 1
    
    PROPERTIES (
    
    "replication_num" = "1"
    
    );
    
    CREATE TABLE dt2 LIKE dt1;
    
    CREATE TABLE dt3 LIKE dt1;
    
    INSERT INTO dt1 VALUES (1, "Emily", 25), (2, "Benjamin", 35), (3, "Olivia", 28), (4, "Alexander", 60), (5, "Ava", 17);
    
    INSERT INTO dt2 VALUES (6, "William", 69), (7, "Sophia", 32), (8, "James", 64), (9, "Emma", 37), (10, "Liam", 64);
    
    
    
    # 事务写
    
    BEGIN;
    
    INSERT INTO dt2 SELECT * FROM dt1;
    
    INSERT INTO dt3 SELECT * FROM dt2;
    
    COMMIT;
    
    
    
    # 查询
    
    mysql> SELECT * FROM dt2;
    
    +------+-----------+-------+
    
    | id | name | score |
    
    +------+-----------+-------+
    
    | 6 | William | 69 |
    
    | 7 | Sophia | 32 |
    
    | 8 | James | 64 |
    
    | 9 | Emma | 37 |
    
    | 10 | Liam | 64 |
    
    | 1 | Emily | 25 |
    
    | 2 | Benjamin | 35 |
    
    | 3 | Olivia | 28 |
    
    | 4 | Alexander | 60 |
    
    | 5 | Ava | 17 |
    
    +------+-----------+-------+
    
    10 rows in set (0.01 sec)
    
    
    
    mysql> SELECT * FROM dt3;
    
    +------+---------+-------+
    
    | id | name | score |
    
    +------+---------+-------+
    
    | 6 | William | 69 |
    
    | 7 | Sophia | 32 |
    
    | 8 | James | 64 |
    
    | 9 | Emma | 37 |
    
    | 10 | Liam | 64 |
    
    +------+---------+-------+
    
    5 rows in set (0.01 sec)
事务中执行失败的语句

当事务中的某个语句执行失败时,这个操作已经自动回滚。然而,事务中其它执行成功的语句,仍然是可提交或回滚的。当事务被成功提交后,事务中执行成功的语句的修改被应用。

比如:

sql 复制代码
​
mysql> BEGIN;

Query OK, 0 rows affected (0.00 sec)

{'label':'txn_insert_c5940d31bf364f57-a48b628886415442', 'status':'PREPARE', 'txnId':''}

mysql> INSERT INTO dt3 SELECT * FROM dt1;

Query OK, 5 rows affected (0.07 sec)

{'label':'txn_insert_c5940d31bf364f57-a48b628886415442', 'status':'PREPARE', 'txnId':'11058'}

# 失败的写入自动回滚

mysql> INSERT INTO dt3 SELECT * FROM dt2;

ERROR 5025 (HY000): Insert has filtered data in strict mode, tracking_url=http://xxxx:9082/api/_load_error_log?file=__shard_3/error_log_insert_stmt_3d1fed266ce443f2-b54d2609c2ea6b11_3d1fed266ce443f2_b54d2609c2ea6b11

mysql> INSERT INTO dt3 SELECT * FROM dt2 WHERE id = 7;

Query OK, 0 rows affected (0.07 sec)

mysql> COMMIT;

Query OK, 0 rows affected (0.02 sec)

{'label':'txn_insert_c5940d31bf364f57-a48b628886415442', 'status':'VISIBLE', 'txnId':'11058'}

​

查询:

sql 复制代码
# dt1 的数据被写入到 dt3 中,dt2 中 id = 7的数据写入成功,其它写入失败

mysql> SELECT * FROM dt3;

+------+----------+-------+

| id | name | score |

+------+----------+-------+

| 1 | Emily | 25 |

| 2 | Benjamin | 35 |

| 3 | Olivia | 28 |

| 4 | Alexande | 60 |

| 5 | Ava | 17 |

| 7 | Sophia | 32 |

+------+----------+-------+

6 rows in set (0.01 sec)
常见问题
  • 写入的多表必须属于同一个 Database,否则会遇到错误 ``Transaction insert must be in the same database

  • 两种事务写入``INSERT INTO SELECT``, ``UPDATE``, ``DELETE`` 和 ``INSET INTO VALUES`` 不能混用,否则会遇到错误 ``Transaction insert can not insert into values and insert into select at the same time

  • Delete 操作提供了通过谓词和 Using 子句两种方式,为了保证隔离级别,在一个事务中,对相同表的删除必须在写入前,否则会遇到报错 ``Can not delete because there is a insert operation for the same table

  • 当从 ``BEGIN`` 开始的导入耗时超出 Doris 配置的 timeout 时,会导致事务回滚,导入失败。目前 timeout 使用的是 Session 变量 ``insert_timeout`` 和 ``query_timeout`` 的最大值

  • 当使用 JDBC 连接 Doris 进行事务操作时,请在 JDBC URL 中添加 ``useLocalSessionState=true``,否则可能会遇到错误 ``This is in a transaction, only insert, update, delete, commit, rollback is acceptable.

  • 存算分离模式下,事务写不支持 Merge-on-Write 表,否则会遇到报错 ``Transaction load is not supported for merge on write unique keys table in cloud mode

与 MySQL差异

隔离级别

  • MySQL 支持多种事务隔离级别,包括 READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。
  • Doris 目前只支持 READ COMMITTED 隔离级别 。

显式事务

  • MySQL 允许用户通过 BEGIN、COMMIT 和 ROLLBACK 语句显式地控制事务。
  • Doris 也支持显式事务,但目前不支持在多语句事务中包含 DDL 和查询语句 。

隐式事务

  • MySQL 的每个自动提交的 SQL 语句都被视为一个隐式事务。
  • Doris 中的每个导入语句也是一个隐式事务,它在执行开始时自动开启,并在执行完成后自动提交或在失败时自动回滚 。

嵌套事务

  • MySQL 支持嵌套事务。
  • Doris 不支持嵌套事务 。

事务写入

  • Doris 支持两种事务写入方式:单表多次 INSERT INTO VALUES 写入和多表 INSERT INTO SELECTUPDATEDELETE 写入 。

事务中的 DELETE 和 INSERT 操作

  • 在 Doris 中,如果一个事务包含对同一表的 DELETEINSERT 操作,DELETE 操作必须在 INSERT 操作之前 。

事务超时

  • Doris 中,如果从 BEGIN 语句开始的事务执行时间超过了配置的超时时间,事务将被自动回滚 。

JDBC 连接

  • 使用 JDBC 连接 Doris 进行事务操作时,需要在 JDBC URL 中添加 useLocalSessionState=true 参数 。

Stream Load 2PC

  • Doris 支持 Stream Load 2PC 以支持 Flink 写入时的 exactly-once 语义

索引

数据库索引是用于查询加速的,为了加速不同的查询场景,Apache Doris 支持了多种丰富的索引。

索引分类和原理

从加速的查询和原理来看,Apache Doris 的索引分为点查索引和跳数索引两大类。

点查索引

常用于加速点查,原理是通过索引定位到满足 WHERE 条件的有哪些行,直接读取那些行。点查索引在满足条件的行比较少时效果很好。Apache Doris 的点查索引包括前缀索引和倒排索引。

前缀索引

Apache Doris 按照排序键以有序的方式存储数据,并每隔 1024 行数据创建一个稀疏前缀索引。索引中的 Key 是当前 1024 行中第一行中排序列的值。如果查询涉及已排序列,系统将找到相关 1024 行组的第一行并从那里开始扫描。

倒排索引

对创建了倒排索引的列,建立每个值到对应行号集合的倒排表。对于等值查询,先从倒排表中查到行号集合,然后直接读取对应行的数据,而不用逐行扫描匹配数据,从而减少 I/O 加速查询。倒排索引还能加速范围过滤、文本关键词匹配,算法更加复杂但是基本原理类似。(备注:之前的 BITMAP 索引已经被更强的倒排索引取代)

跳数索引

常用于加速分析,原理是通过索引确定不满足 WHERE 条件的数据块,跳过这些不满足条件的数据块,只读取可能满足条件的数据块并再进行一次逐行过滤,最终得到满足条件的行。跳数索引在满足条件的行比较多时效果较好。Apache Doris 的跳数索引包括 ZoneMap 索引、BloomFilter 索引、NGram BloomFilter 索引。

ZoneMap 索引

自动维护每一列的统计信息,为每一个数据文件(Segment)和数据块(Page)记录最大值、最小值、是否有 NULL。对于等值查询、范围查询、IS NULL,可以通过最大值、最小值、是否有 NULL 来判断数据文件和数据块是否可以包含满足条件的数据,如果没有则跳过不读对应的文件或数据块减少 I/O 加速查询。

BloomFilter 索引

将索引对应列的可能取值存入 BloomFilter 数据结构中,它可以快速判断一个值是否在 BloomFilter 里面,并且 BloomFilter 存储空间占用很低。对于等值查询,如果判断这个值不在 BloomFilter 里面,就可以跳过对应的数据文件或者数据块减少 I/O 加速查询。

NGram BloomFilter 索引

用于加速文本 LIKE 查询,基本原理与 BloomFilter 索引类似,只是存入 BloomFilter 的不是原始文本的值,而是对文本进行 NGram 分词,每个词作为值存入 BloomFilter。对于 LIKE 查询,将 LIKE 的 pattern 也进行 NGram 分词,判断每个词是否在 BloomFilter 中,如果某个词不在则对应的数据文件或者数据块就不满足 LIKE 条件,可以跳过这部分数据减少 I/O 加速查询。

上述索引中,前缀索引和 ZoneMap 索引是 Apache Doris 自动维护的内建智能索引,无需用户管理,而倒排索引、BloomFilter 索引、NGram BloomFilter 索引则需要用户自己根据场景选择,手动创建、删除。

类型 索引 加速等于 加速不等 加速范围 加速 LIKE 加速 MATCH(关键词、短语) 优点 局限
点查索引 前缀索引 YES YES YES NO NO 最常用的过滤条件 一个表只有一个前缀索引
点查索引 倒排索引 YES YES YES COMING YES 支持分词和关键词匹配,任意列可建索引,多条件组合 索引存储空间较大,与原始数据相当
跳数索引 ZoneMap 索引 YES YES YES NO NO 内置索引,索引存储空间小 N/A
跳数索引 BloomFilter 索引 YES NO NO NO NO 比 ZoneMap 更精细,索引空间较小 支持的查询类型少,只支持等于,不支持其他(不等、范围、LIKE、MATCH)
跳数索引 NGram BloomFilter 索引 NO NO NO YES NO 支持 LIKE 加速,索引空间较小 只支持 LIKE 加速

与MySql差异

索引类型

MySQL 支持 B-Tree、Hash、R-Tree 等索引类型,其中 B-Tree 索引是最常用的类型,适合全值匹配、范围查询、索引顺序访问和索引列比较。

Doris 支持前缀索引、倒排索引、ZoneMap 索引、BloomFilter 索引和 NGram BloomFilter 索引。前缀索引和 ZoneMap 索引是自动维护的,而倒排索引、BloomFilter 索引和 NGram BloomFilter 索引需要用户手动创建 。

索引创建

在 MySQL 中,可以通过 ALTER TABLECREATE INDEX 语句创建索引。

Doris 同样支持 ALTER TABLE ADD INDEX 语句来创建索引,但不支持 CREATE INDEX 单独创建索引的语法 。

索引使用

MySQL 使用索引来优化查询性能,索引可以显著减少查询中需要扫描的数据行数。

Doris 的索引设计用于优化 OLAP 查询,特别是列式存储的优化。Doris 的前缀索引和 ZoneMap 索引是自动创建的,用于加速等值查询和范围查询 。

索引与数据模型的配合

MySQL 通过索引来优化查询,但并没有数据模型的概念。

Doris 的数据模型(如 DUPLICATE KEY、AGGREGATE KEY、UNIQUE KEY)会影响索引的使用和查询优化。

索引的适用场景

MySQL 的索引适用于各种查询类型,包括点查询、范围查询和 JOIN 操作。

Doris 的索引更专注于优化 OLAP 查询,特别是对于大数据量的分析型查询。

索引的局限性

MySQL 的索引可能会因为数据类型转换或使用了某些函数而失效。

Doris 的倒排索引和 BloomFilter 索引有其特定的适用场景和局限性,例如倒排索引适用于文本搜索,而 BloomFilter 索引适用于等值查询。

索引维护

MySQL 需要用户手动创建和维护索引。

Doris 自动维护某些索引,如前缀索引和 ZoneMap 索引,而其他索引如倒排索引和 BloomFilter 索引需要用户根据需求手动创建。

未完待续。。。。

相关推荐
小城里的梦想几秒前
redis和mysql端口修改
数据库·redis·mysql
光锥智能11 分钟前
OceanBase云数据库战略实施两年,受零售、支付、制造行业青睐
数据库·oceanbase·零售
赤鸢QAQ27 分钟前
pyqt瀑布流布局
数据库·pyqt
深科信项目申报助手38 分钟前
“国家高新”与“专精特新”企业的对比分析
大数据·经验分享·科技·其他·制造
极客先躯40 分钟前
高级java每日一道面试题-2024年9月29日-数据库篇-索引怎么定义,分哪几种?
java·数据结构·数据库·分类·索引·全文索引·聚集索引
是店小二呀1 小时前
【C++】面向对象编程的三大特性:深入解析多态机制
开发语言·c++·后端
三品软件1 小时前
制造企业为何需要PLM系统?PLM系统解决方案对制造业重要性分析
大数据·运维·人工智能·物联网·自动化·制造
F_D_Z1 小时前
【SQL】重复的邮箱信息
数据库·sql
Jasonakeke1 小时前
【重学 MySQL】四十、SQL 语句执行过程
数据库·sql·mysql