3.8 Schema 变更¶
用户可以通过 Schema Change
操作来修改已存在表的 Schema
。表的 Schema
,主要包括对列的修改和索引的改动,这里主要介绍列相关的 Scheme
变更,关于索引相关的变更,可以查看数据表设计或表索引来查看每种索引的变更方式。
1 名词解释¶
-
Base Table
:基表。使用建表语句创建出的原始表。 -
Rollup
:基于基表或者其他Rollup
创建出来的上卷表。 -
Index
:物化索引。Rollup
和Base Table
都被称为物化索引。 -
Transaction
:事务。每一个导入任务都对应一个事务,每个事务有一个唯一递增的Transaction ID
。
2 原理介绍¶
2.1 概览¶
Schema Change
的实现分为两个大类:轻量级 Schema Change
和重量级 Schema Change
。
-
轻量级
Schema Change
完成速度很快,只会同步地修改FE
的元数据,一般在秒级别完成。增加或删除value
列、更改列名、增加除DUP KEY
列和UNIQUE KEY
列以外的VARCHAR
列的长度,都会使用轻量级Schema Change
的逻辑。 -
重量级
Schema Change
需要依赖BE
进行数据文件的转换。具体实现方式如下:Schema change实现 主要逻辑 使用场景 Direct Schema Change 对数据文件进行整体重写,但是不会涉及重排序 更改value列的数据类型 Sort Schema Change 对数据文件进行整体重写,并进行重排序 更改key列的数据类型 Hard Linked Schema Change 对数据文件进行重新链接,不需要直接修改数据文件 在列的变更中被轻量级Schema Change取代
2.2 主要流程¶
对于轻量级 Schema Change
,只会在 Alter
命令发起后修改 FE
的相应元数据, Alter
命令的返回就代表 Schema
变更的结束。
对于重量级 Schema Change
,在用户发起 Alter
命令后,会在后台启动一个任务进行 Schema
的变更,命令的返回代表着 Schema
变更任务的提交成功。后台任务的执行将经过以下过程:
-
对目标表的每个
tablet
,都根据变更后的schema
创建对应的new tablet
,用于存放转换后的数据。 -
等待先前的所有导入事务结束,才能开始数据转换。
-
开始数据转换,按
tablet
为任务单位,把每个旧tablet
上的数据经过变更写入到之前新建的tablet
上。三种重量级Schema Change
的差异在这一步上,会通过上文提到的各自实现逻辑进行数据转换。 -
数据转换开始后,如果有新的导入事务创建,为保证数据完整性,新的导入事务将同时为旧
tablet
和新tablet
生成数据,即数据双写。双写期间的数据必须兼容新、旧Schema
,否则会导入失败。SQL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+----------+ | Load Job | +----+-----+ | | Load job generates both origin and new Index data | | +------------------+ +---------------+ | | Origin Index | | Origin Index | +------> New Incoming Data| | History Data | | +------------------+ +------+--------+ | | | | Convert history data | | | +------------------+ +------v--------+ | | New Index | | New Index | +------> New Incoming Data| | History Data | +------------------+ +---------------+
-
数据转换完成后,所有存放旧数据的
tablet
将会被删除,所有完成数据变更的新tablet
将会取代旧tablet
进行服务。
创建 Schema Change
的具体语法可以查看帮助 ALTER TABLE COLUMN
中 Schema Change
部分的说明。
3 向指定 Index 的指定位置添加一列¶
3.1 语法¶
SQL | |
---|---|
1 2 3 4 |
|
-
聚合模型如果增加
Value
列,需要指定agg_type
-
非聚合模型(如
DUPLICATE KEY
)如果增加Key
列,需要指定KEY
关键字 -
不能在
Rollup Index
中增加Base Index
中已经存在的列(如有需要,可以重新创建一个Rollup Index
)
3.2 示例¶
3.2.1 非聚合模型¶
建表语句:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
-
向
example_rollup_index
的col1
后添加一个Key
列new_col
SQL 1 2 3
ALTER TABLE example_db.my_table ADD COLUMN new_col INT KEY DEFAULT "0" AFTER col1 TO example_rollup_index;
-
向
example_rollup_index
的col1
后添加一个Value
列new_col
SQL 1 2 3
ALTER TABLE example_db.my_table ADD COLUMN new_col INT DEFAULT "0" AFTER col1 TO example_rollup_index;
3.2.2 聚合模型¶
建表语句:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
-
向
example_rollup_index
的col1
后添加一个Key
列new_col
SQL 1 2 3
ALTER TABLE example_db.my_table ADD COLUMN new_col INT DEFAULT "0" AFTER col1 TO example_rollup_index;
-
向
example_rollup_index
的col1
后添加一个Value
列new_col
SUM
聚合类型SQL 1 2 3
ALTER TABLE example_db.my_table ADD COLUMN new_col INT SUM DEFAULT "0" AFTER col1 TO example_rollup_index;
4 向指定 Index 添加多列¶
4.1 语法¶
SQL | |
---|---|
1 2 3 |
|
-
聚合模型如果增加
Value
列,需要指定agg_type
-
聚合模型如果增加
Key
列,需要指定KEY
关键字 -
不能在
Rollup Index
中增加Base Table
中已经存在的列(如有需要,可以重新创建一个Rollup Index
)
4.2 示例¶
向 example_rollup_index
添加多列(聚合模型)
SQL | |
---|---|
1 2 3 |
|
5 从指定 Index 中删除一列¶
5.1 语法¶
SQL | |
---|---|
1 2 |
|
-
不能删除分区列
-
如果是从
Base Table
中删除列,则如果Rollup Index
中包含该列,也会被删除
5.2 示例¶
从 example_rollup_index
删除一列
SQL | |
---|---|
1 2 3 |
|
6 修改指定 Index 的列类型以及列位置¶
6.1 语法¶
SQL | |
---|---|
1 2 3 4 |
|
-
聚合模型如果修改
Value
列,需要指定agg_type
-
非聚合类型如果修改
Key
列,需要指定KEY
关键字 -
只能修改列的类型,列的其他属性维持原样(即其他属性需在语句中按照原属性显式的写出,参见
Example 8
) -
分区列和分桶列不能做任何修改
-
目前支持以下类型的转换(用户需要注意精度损失)
-
TINYINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE
类型向范围更大的数字类型转换 -
TINTINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE/DECIMAL
转换成VARCHAR
-
VARCHAR
支持修改最大长度 -
VARCHAR/CHAR
转换成TINTINT/SMALLINT/INT/BIGINT/LARGEINT/FLOAT/DOUBLE
-
VARCHAR/CHAR
转换成DATE
(目前支持"%Y-%m-%d"
,"%y-%m-%d"
,"%Y%m%d"
,"%y%m%d"
,"%Y/%m/%d"
,"%y/%m/%d"
六种格式化格式) -
DATETIME
转换成DATE
(仅保留年月日信息,例如:2019-12-09 21:47:05
转换成2019-12-09
) -
DATE
转换成DATETIME
(时分秒自动补零,例如:2019-12-09
转换成2019-12-09 00:00:00
) -
FLOAT
转换成DOUBLE
-
INT
转换成DATE
(如果INT
类型数据不合法则转换失败,原始数据不变) -
除
DATE
与DATETIME
以外都可以转换成STRING
,但是STRING
不能转换任何其他类型
-
6.2 示例¶
建表语句:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 |
|
-
修改
Base Index
的Key
列col1
的类型为BIGINT
,并移动到col2
列后面。SQL 1 2
ALTER TABLE example_db.my_table MODIFY COLUMN col1 BIGINT KEY DEFAULT "1" AFTER col2;
注意:无论是修改
Key
列还是Value
列都需要声明完整的Column
信息 -
修改
Base Index
的val1
列最大长度。原val1
为(val1 VARCHAR(32) REPLACE DEFAULT "abc")
SQL 1 2
ALTER TABLE example_db.my_table MODIFY COLUMN col5 VARCHAR(64) REPLACE DEFAULT "abc";
注意:只能修改列的类型,列的其他属性需要维持原样
-
修改
Duplicate Key
表Key
列的某个字段的长度SQL 1 2
ALTER TABLE example_db.my_table MODIFY COLUMN col3 varchar(50) KEY NULL comment 'to 50'
7 对指定 Index 的列进行重新排序¶
7.1 语法¶
SQL | |
---|---|
1 2 3 |
|
-
Index
中的所有列都要写出来 -
Value
列在Key
列之后
7.2 示例¶
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
重新排序 example_rollup_index
中的列(设原列顺序为: k1, k2, k3, v1, v2
)
SQL | |
---|---|
1 2 3 |
|
8 一次提交进行多种变更¶
Schema Change
可以在一个作业中,对多个 Index
进行不同的修改。
8.1 示例 1¶
源 Schema
:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
可以通过以下命令给 rollup1
和 rollup2
都加入一列 k4
,并且再给 rollup2
加入一列 k5
:
SQL | |
---|---|
1 2 3 4 |
|
完成后, Schema
变为:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
可以看到, Base
表 tbl1
也自动加入了 k4
, k5
列。即给任意 Rollup
增加的列,都会自动加入到 Base
表中。
同时,不允许向 Rollup
中加入 Base
表已经存在的列。如果用户需要这样做,可以重新建立一个包含新增列的 Rollup
,之后再删除原 Rollup
。
8.2 示例 2¶
建表语句
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
SQL | |
---|---|
1 2 3 |
|
9 修改列名称¶
9.1 语法¶
SQL | |
---|---|
1 |
|
10 查看作业¶
用户可以通过 SHOW ALTER TABLE COLUMN
命令来查看 schema change
作业进度。
SHOW ALTER TABLE COLUMN
可以查看当前正在执行或已经完成的 Schema Change
作业。当一次 Schema Change
作业涉及到多个 Index
时,该命令会显示多行,每行对应一个 Index
。举例如下:
SQL | |
---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
-
JobId
:每个Schema Change
作业的唯一ID
。 -
TableName
:Schema Change
对应的基表的表名。 -
CreateTime
:作业创建时间。 -
FinishedTime
:作业结束时间。如未结束,则显示"N/A"
。 -
IndexName
:本次修改所涉及的某一个Index
的名称。 -
IndexId
:新的Index
的唯一ID
。 -
OriginIndexId
:旧的Index
的唯一ID
。 -
SchemaVersion
:以M:N
的格式展示。其中M
表示本次Schema Change
变更的版本,N
表示对应的Hash
值。每次Schema Change
,版本都会递增。 -
TransactionId
:转换历史数据的分水岭Transaction ID
。 -
State
:作业所在阶段。-
PENDING
:作业在队列中等待被调度。 -
WAITING_TXN
:等待分水岭Transaction ID
之前的导入任务完成。 -
RUNNING
:历史数据转换中。 -
FINISHED
:作业成功。 -
CANCELLED
:作业失败。
-
-
Msg
:如果作业失败,这里会显示失败信息。 -
Progress
:作业进度。只有在RUNNING
状态才会显示进度。进度是以M/N
的形式显示。其中N
为Schema Change
涉及的总副本数。M
为已完成历史数据转换的副本数。 -
Timeout
:作业超时时间。单位秒。
11 取消作业¶
在作业状态不为 FINISHED
或 CANCELLED
的情况下,可以通过以下命令取消 Schema Change
作业:
SQL | |
---|---|
1 |
|
12 注意事项¶
-
一张表在同一时间只能有一个
Schema Change
作业在运行。 -
Schema Change
操作不阻塞导入和查询操作。除非操作本身影响了表的元数据(例如自动分区表导入过程中创建了分区) -
分区列和分桶列不能修改。
-
如果
Schema
中有REPLACE
方式聚合的Value
列,则不允许删除Key
列。 -
如果删除
Key
列,Doris
无法决定REPLACE
列的取值。 -
Unique
数据模型表的所有非Key
列都是REPLACE
聚合方式。 -
在新增聚合类型为
SUM
或者REPLACE
的Value
列时,该列的默认值对历史数据没有含义。 -
因为历史数据已经失去明细信息,所以默认值的取值并不能实际反映聚合后的取值。
-
当修改列类型时,除
Type
以外的字段都需要按原列上的信息补全。 -
如修改列
k1 INT SUM NULL DEFAULT "1"
类型为BIGINT
,则需执行命令如下: -
ALTER TABLE tbl1 MODIFY COLUMNk1BIGINT SUM NULL DEFAULT "1";
-
注意,除新的列类型外,如聚合方式,
Nullable
属性,以及默认值都要按照原信息补全。 -
不支持修改聚合类型、
Nullable
属性、默认值。
13 常见问题¶
Schema Change
的执行速度
Light Schema Change
,即如果是增加和删除 Value
列,则可以毫秒级返回。其它的 Schema Change
执行速度按照最差效率估计约为 10MB/s
。保守起见,用户可以根据这个速率来设置作业的超时时间。
提交作业报错 Table xxx is not stable. ...
Schema Change
只有在表数据完整且非均衡状态下才可以开始。如果表的某些数据分片副本不完整,或者某些副本正在进行均衡操作,则提交会被拒绝。数据分片副本是否完整,可以通过以下命令查看:
SQL | |
---|---|
1 |
|
如果有返回结果,则说明有副本有问题。通常系统会自动修复这些问题,用户也可以通过以下命令优先修复这个表:
SQL | |
---|---|
1 |
|
用户可以通过以下命令查看是否有正在运行的均衡任务:
SQL | |
---|---|
1 |
|
可以等待均衡任务完成,或者通过以下命令临时禁止均衡操作:
SQL | |
---|---|
1 |
|
14 相关配置¶
14.1 FE 配置¶
alter_table_timeout_second
:作业默认超时时间,86400
秒。
14.2 BE 配置¶
-
alter_tablet_worker_count
:在BE
端用于执行历史数据转换的线程数。默认为3
。如果希望加快Schema Change
作业的速度,可以适当调大这个参数后重启BE
。但过多的转换线程可能会导致IO
压力增加,影响其他操作。该线程和Rollup
作业共用。 -
alter_index_worker_count
:在BE
端用于执行历史数据构建索引的线程数(注:当前只支持倒排索引)。默认为3
。如果希望加快Index Change
作业的速度,可以适当调大这个参数后重启BE
。但过多的线程可能会导致IO
压力增加,影响其他操作。
15 更多参考¶
关于 Schema Change
使用的更多详细语法及最佳实践,请参阅 ALTER TABLE COLUMN
命令手册。