表結(jié)構(gòu)變更
當(dāng)您需要對(duì)云數(shù)據(jù)庫(kù) SelectDB 版數(shù)據(jù)庫(kù)表結(jié)構(gòu)進(jìn)行調(diào)整以適應(yīng)新的業(yè)務(wù)需求時(shí),本文檔提供了詳細(xì)的變更表結(jié)構(gòu)操作指南以及注意事項(xiàng),以幫助您完成表結(jié)構(gòu)變更。
概述
通過(guò)結(jié)構(gòu)(Schema)變更操作來(lái)修改已存在表的結(jié)構(gòu)(Schema),支持以下幾種修改方式。
增加、刪除列。
修改列類型。
調(diào)整列順序。
增加、修改BloomFilter Index。
增加、刪除Bitmap Index。
名詞解釋
BASE Table:基表。每一個(gè)表被創(chuàng)建時(shí),都對(duì)應(yīng)一個(gè)基表。
ROLLUP:上卷表。基于基表或者其他ROLLUP創(chuàng)建出來(lái)的上卷表。
Index:物化索引。ROLLUP或BASE Table都被稱為物化索引。
Transaction:事務(wù)。每一個(gè)導(dǎo)入任務(wù)都是一個(gè)事務(wù),每個(gè)事務(wù)有一個(gè)唯一遞增的Transaction ID。
基本原理
執(zhí)行Schema變更的基本過(guò)程,是通過(guò)原Index的數(shù)據(jù),生成一份新Schema的Index數(shù)據(jù)。主要進(jìn)行兩部分?jǐn)?shù)據(jù)轉(zhuǎn)換,一是已存在的歷史數(shù)據(jù)的轉(zhuǎn)換,二是在Schema變更執(zhí)行過(guò)程中,新導(dǎo)入數(shù)據(jù)的轉(zhuǎn)換。
+----------+
| 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 |
+------------------+ +---------------+
在開(kāi)始轉(zhuǎn)換歷史數(shù)據(jù)前,SelectDB會(huì)獲取一個(gè)最新的Transaction ID。并等待這個(gè)Transaction ID之前的所有導(dǎo)入事務(wù)完成。這個(gè)Transaction ID稱為分水嶺。SelectDB保證在分水嶺之后的所有導(dǎo)入任務(wù),都會(huì)同時(shí)為原Index和新Index生成數(shù)據(jù)。因此當(dāng)歷史數(shù)據(jù)轉(zhuǎn)換完成后,SelectDB可以保證新的Index中的數(shù)據(jù)是完整的。
創(chuàng)建變更作業(yè)
該語(yǔ)句用于對(duì)已有Table進(jìn)行Schema變更操作。Schema變更是異步的,任務(wù)提交成功則返回結(jié)果,提交任務(wù)后可使用SHOW ALTER TABLE COLUMN;
命令查看執(zhí)行進(jìn)度。
語(yǔ)法
ALTER TABLE [database.]table <alter_clause>;
一張表在同一時(shí)間只能有一個(gè)Schema變更作業(yè)在運(yùn)行。
Schema變更操作不阻塞導(dǎo)入和查詢操作。
變更Schema時(shí)不能修改分區(qū)列和分桶列。
如果Schema中有REPLACE方式聚合的Value列,則不允許刪除Key列。
如果刪除Key列,SelectDB將無(wú)法決定REPLACE列的取值。
Unique數(shù)據(jù)模型表的所有非Key列都是REPLACE聚合方式。
新增聚合類型為SUM或者REPLACE的Value列時(shí),該列的默認(rèn)值對(duì)歷史數(shù)據(jù)沒(méi)有意義。
因?yàn)闅v史數(shù)據(jù)已經(jīng)失去詳細(xì)信息,所以默認(rèn)值的取值并不能反映實(shí)際聚合后的取值。
當(dāng)修改列類型時(shí),除Type以外的字段都需要按被修改列上的信息補(bǔ)全。
如修改列
k1 INT SUM NULL DEFAULT "1"
類型為BIGINT,則需執(zhí)行命令如下:ALTER TABLE tbl1 MODIFY COLUMN k1 BIGINT SUM NULL DEFAULT "1";
除新的列類型外,如聚合方式,Nullable屬性,以及默認(rèn)值都要按照原信息補(bǔ)全。
不支持修改列名稱、聚合類型、Nullable屬性、默認(rèn)值以及列注釋。
Schema變更的<alter_clause>支持如下幾種修改方式。
向指定index的指定位置添加一列。
ADD COLUMN column_name column_type [KEY | agg_type] [DEFAULT "default_Value"] [AFTER column_name|FIRST] [TO rollup_index_name] [PROPERTIES ("key"="Value", ...)]
說(shuō)明聚合模型如果增加Value列,需要指定
agg_type
。非聚合模型(如DUPLICATE Key)如果增加Key列,需要指定
KEY
關(guān)鍵字。不能在ROLLUP index中增加BASE index中已經(jīng)存在的列(如果需要在ROLLUP index 中增加BASE index,可以重新創(chuàng)建一個(gè)ROLLUP index)。
向指定Index添加多列。
ADD COLUMN (column_name1 column_type [KEY | agg_type] DEFAULT "default_Value", ...) [TO rollup_index_name] [PROPERTIES ("key"="Value", ...)]
說(shuō)明聚合模型如果增加Value列,需要指定
agg_type
。聚合模型如果增加key列,需要指定
KEY
關(guān)鍵字。不能在ROLLUP index中增加BASE index中已經(jīng)存在的列(如果需要在ROLLUP index 中增加BASE index,可以重新創(chuàng)建一個(gè)ROLLUP index)。
從指定Index中刪除一列。
DROP COLUMN column_name[FROM rollup_index_name]
說(shuō)明不能刪除分區(qū)列。
如果是從BASE index中刪除列,則如果ROLLUP index中包含該列,也會(huì)被刪除。
修改指定Index的列類型以及列位置。
MODIFY COLUMN column_name column_type [KEY | agg_type] [NULL | NOT NULL] [DEFAULT "default_Value"] [AFTER column_name|FIRST] [FROM rollup_index_name] [PROPERTIES ("key"="Value", ...)]
說(shuō)明聚合模型如果修改Value列,需要指定
agg_type
。非聚合類型如果修改Key列,需要指定
KEY
關(guān)鍵字。只能修改列的類型,列的其他屬性維持原樣(其他屬性需要在修改語(yǔ)句中和原屬性保持一致,詳情請(qǐng)參見(jiàn)示例)。
分區(qū)列和分桶列不能做任何修改。
目前支持以下類型的轉(zhuǎn)換(需自行確保精度不會(huì)喪失):
TINYINT、SMALLINT、INT、BIGINT、LARGEINT、FLOAT和DOUBLE類型向范圍更大的數(shù)字類型轉(zhuǎn)換。
TINTINT、SMALLINT、INT、BIGINT、LARGEINT、FLOAT、DOUBLE和DECIMAL轉(zhuǎn)換成VARCHAR類型。
VARCHAR類型支持修改最大長(zhǎng)度。
VARCHAR類型或CHAR類型轉(zhuǎn)換成TINTINT、SMALLINT、INT、BIGINT、LARGEINT、FLOAT和DOUBLE類型。
VARCHAR類型和CHAR類型轉(zhuǎn)換成DATE類型(目前支持"%Y-%m-%d","%y-%m-%d","%Y%m%d","%y%m%d","%Y/%m/%d,"%y/%m/%d"六種格式化格式)。
DATETIME類型轉(zhuǎn)換成DATE類型(僅保留年-月-日信息,例如:
2019-12-09 21:47:05
<-->2019-12-09
)。DATE類型轉(zhuǎn)換成DATETIME類型(時(shí)分秒自動(dòng)補(bǔ)零,例如:
2019-12-09
<-->2019-12-09 00:00:00
)。FLOAT類型轉(zhuǎn)換成DOUBLE類型。
INT類型轉(zhuǎn)換成DATE類型(如果INT類型數(shù)據(jù)不合法則轉(zhuǎn)換失敗,原始數(shù)據(jù)不變)。
除DATE類型與DATETIME類型以外都可以轉(zhuǎn)換成STRING類型,但是STRING類型不能轉(zhuǎn)換任何其他類型。
對(duì)指定Index的列進(jìn)行重新排序。
ORDER BY (column_name1, column_name2, ...) [FROM rollup_index_name] [PROPERTIES ("key"="Value", ...)]
說(shuō)明Index中的所有列都要指明。
Value列在Key列之后。
示例
修改示例表
example_db.my_table
(非聚合模型)的Schema,在example_rollup_index
的col1
后添加一個(gè)Key列new_col
。ALTER TABLE example_db.my_table ADD COLUMN new_col INT KEY DEFAULT "0" AFTER col1 TO example_rollup_index;
修改示例表
example_db.my_table
(非聚合模型)的Schema,在example_rollup_index
的col1
后添加一個(gè)Value列new_col
。ALTER TABLE example_db.my_table ADD COLUMN new_col INT DEFAULT "0" AFTER col1 TO example_rollup_index;
修改示例表
example_db.my_table
(聚合模型)的Schema,向example_rollup_index
的col1
后添加一個(gè)Key列new_col
。ALTER TABLE example_db.my_table ADD COLUMN new_col INT DEFAULT "0" AFTER col1 TO example_rollup_index;
修改示例表
example_db.my_table
(聚合模型)的Schema,向example_rollup_index
的col1
后添加一個(gè)Value列new_col
且聚合類型為 SUM。ALTER TABLE example_db.my_table ADD COLUMN new_col INT SUM DEFAULT "0" AFTER col1 TO example_rollup_index;
修改示例表
example_db.my_table
(聚合模型)的Schema,向example_rollup_index
添加兩列。一個(gè)是Key列col1
,另一個(gè)是Value列col2
且聚合類型為 SUM。ALTER TABLE example_db.my_table ADD COLUMN (col1 INT DEFAULT "1", col2 FLOAT SUM DEFAULT "2.3") TO example_rollup_index;
修改示例表
example_db.my_table
的Schema,從example_rollup_index
刪除一列。ALTER TABLE example_db.my_table DROP COLUMN col2 FROM example_rollup_index;
修改示例表
example_db.my_table
的Schema,修改BASE index的Key列col1
的類型為BIGINT
,并移動(dòng)到col2
列后面。ALTER TABLE example_db.my_table MODIFY COLUMN col1 BIGINT KEY DEFAULT "1" AFTER col2;
說(shuō)明無(wú)論是修改Key列還是Value列都需要聲明完整的COLUMN信息。
修改示例表
example_db.my_table
的Schema,修改BASE index的val1
列最大長(zhǎng)度,從VARCHAR(32)
修改為VARCHAR(64)
。ALTER TABLE example_db.my_table MODIFY COLUMN val1 VARCHAR(64) REPLACE DEFAULT "abc";
修改示例表
example_db.my_table
的Schema,重新排序example_rollup_index
中的列(設(shè)原列順序?yàn)椋簁1,k2,k3,v1,v2)。ALTER TABLE example_db.my_table ORDER BY (k3,k1,k2,v2,v1) FROM example_rollup_index;
修改Duplicate Key表Key列的某個(gè)字段的長(zhǎng)度。
原Schema如下。
+-----------+-------+-------------+------+------+---------+-------+ | IndexName | Field | Type | Null | Key | Default | Extra | +-----------+-------+-------------+------+------+---------+-------+ | tbl1 | k1 | INT | No | true | N/A | | | | k2 | INT | No | true | N/A | | | | k3 | varchar(20) | No | true | N/A | | | | k4 | INT | No | false| N/A | | +-----------+-------+-------------+------+------+---------+-------+
將
k3
列的長(zhǎng)度改成50,修改語(yǔ)句如下。ALTER TABLE example_tbl MODIFY COLUMN k3 varchar(50) key null COMMENT 'to 50'
修改完成后,Schema如下。
+-----------+-------+-------------+------+------+---------+-------+ | IndexName | Field | Type | Null | Key | Default | Extra | +-----------+-------+-------------+------+------+---------+-------+ | tbl1 | k1 | INT | No | true | N/A | | | | k2 | INT | No | true | N/A | | | | k3 | varchar(50) | No | true | N/A | | | | k4 | INT | No | false| N/A | | +-----------+-------+-------------+------+------+---------+-------+
因?yàn)镾chema變更作業(yè)是異步操作,同一個(gè)表同時(shí)只能進(jìn)行一個(gè)Schema變更作業(yè)。
在一個(gè)作業(yè)中,對(duì)多個(gè)ROLLUP進(jìn)行不同的修改。
原Schema如下。
+-----------+-------+------+------+------+---------+-------+ | IndexName | Field | Type | Null | Key | Default | Extra | +-----------+-------+------+------+------+---------+-------+ | tbl1 | k1 | INT | No | true | N/A | | | | k2 | INT | No | true | N/A | | | | k3 | INT | No | true | N/A | | | | | | | | | | | rollup2 | k2 | INT | No | true | N/A | | | | | | | | | | | rollup1 | k1 | INT | No | true | N/A | | | | k2 | INT | No | true | N/A | | +-----------+-------+------+------+------+---------+-------+
通過(guò)以下命令給
rollup1
和rollup2
都加入一列k4
,并且再給rollup2
加入一列k5
。ALTER TABLE tbl1 ADD COLUMN k4 INT default "1" to rollup1, ADD COLUMN k4 INT default "1" to rollup2, ADD COLUMN k5 INT default "1" to rollup2;
修改完成后,Schema如下。
+-----------+-------+------+------+------+---------+-------+ | IndexName | Field | Type | Null | Key | Default | Extra | +-----------+-------+------+------+------+---------+-------+ | tbl1 | k1 | INT | No | true | N/A | | | | k2 | INT | No | true | N/A | | | | k3 | INT | No | true | N/A | | | | k4 | INT | No | true | 1 | | | | k5 | INT | No | true | 1 | | | | | | | | | | | rollup2 | k2 | INT | No | true | N/A | | | | k4 | INT | No | true | 1 | | | | k5 | INT | No | true | 1 | | | | | | | | | | | rollup1 | k1 | INT | No | true | N/A | | | | k2 | INT | No | true | N/A | | | | k4 | INT | No | true | 1 | | +-----------+-------+------+------+------+---------+-------+
BASE表
tbl1
也自動(dòng)加入了k4,k5
列。即給任意ROLLUP增加的列,都會(huì)自動(dòng)加入到BASE表中。同時(shí),不允許向ROLLUP中加入BASE表已經(jīng)存在的列。如果需要在ROLLUP index 中增加BASE index,可以重新創(chuàng)建一個(gè)ROLLUP index,之后再刪除原ROLLUP。
查看變更作業(yè)
查看變更作業(yè),查看正在執(zhí)行或已經(jīng)完成的Schema變更作業(yè)。當(dāng)一次Schema變更作業(yè)涉及到多個(gè)Index 時(shí),該命令會(huì)顯示多行,每行對(duì)應(yīng)一個(gè)Index。
語(yǔ)法
SHOW ALTER TABLE COLUMN;
示例
SHOW ALTER TABLE COLUMN\G;
*************************** 1. row ***************************
JobId: 20021
TableName: tbl1
CreateTime: 2019-08-05 23:03:13
FinishTime: 2019-08-05 23:03:42
IndexName: tbl1
IndexId: 20022
OriginIndexId: 20017
SchemaVersion: 2:792557838
TransactionId: 10023
State: FINISHED
Msg:
Progress: NULL
Timeout: 86400
1 row in set (0.00 sec)
各個(gè)列代表的含義如下
參數(shù)名稱 | 描述 |
JobId | 每個(gè)Schema變更作業(yè)的唯一ID。 |
TableName | Schema變更對(duì)應(yīng)的BASE表的表名。 |
CreateTime | 作業(yè)創(chuàng)建時(shí)間。 |
FinishedTime | 作業(yè)結(jié)束時(shí)間。如未結(jié)束,則顯示“N/A”。 |
IndexName | 本次修改所涉及的某一個(gè)Index的名稱。 |
IndexId | 新的Index的唯一ID。 |
OriginIndexId | 舊的Index的唯一ID。 |
SchemaVersion | 以M:N的格式展示。其中M表示本次Schema變更的版本,N表示對(duì)應(yīng)的哈希值。每次Schema變更,版本都會(huì)遞增。 |
State | 作業(yè)所在階段。
|
Msg | 如果作業(yè)失敗,這里會(huì)顯示失敗信息。 |
Progress | 作業(yè)進(jìn)度。只有在RUNNING狀態(tài)才會(huì)顯示進(jìn)度。進(jìn)度是以M/N的形式顯示。其中N為Schema變更涉及的總副本數(shù)。M為已完成歷史數(shù)據(jù)轉(zhuǎn)換的副本數(shù)。 |
Timeout | 作業(yè)超時(shí)時(shí)間。單位秒。 |
取消變更作業(yè)
取消變更作業(yè),在作業(yè)狀態(tài)不為FINISHED或CANCELLED的情況下,可以通過(guò)以下命令取消Schema變更作業(yè)。
語(yǔ)法
CANCEL ALTER TABLE COLUMN FROM <tbl_name>;
參數(shù)說(shuō)明
參數(shù)名稱 | 參數(shù)說(shuō)明 |
tbl_name | 表名稱。 |
示例
撤銷針對(duì)示例表example_db.my_table
的ALTER COLUMN操作。
CANCEL ALTER TABLE COLUMN FROM example_db.my_table;
相關(guān)配置?
FE配置??
alter_table_timeout_second
:作業(yè)默認(rèn)超時(shí)時(shí)間,默認(rèn)為86400秒。
BE配置?
alter_tablet_worker_count
:在BE端用于執(zhí)行歷史數(shù)據(jù)轉(zhuǎn)換的線程數(shù),默認(rèn)為3。如果希望加快Schema變更作業(yè)的速度,可以適當(dāng)調(diào)大這個(gè)參數(shù)后重啟BE。但過(guò)多的轉(zhuǎn)換線程可能會(huì)導(dǎo)致IO壓力增加,影響其他操作。該線程和ROLLUP作業(yè)共用。alter_index_worker_count
:在BE端用于執(zhí)行歷史數(shù)據(jù)構(gòu)建索引的線程數(shù)。默認(rèn)為3。如果希望加快Index變更作業(yè)的速度,可以適當(dāng)調(diào)大這個(gè)參數(shù)后重啟BE。但過(guò)多的線程可能會(huì)導(dǎo)致IO壓力增加,影響其他操作。說(shuō)明該參數(shù)只支持倒排索引。
常見(jiàn)問(wèn)題?
Q:Schema變更的執(zhí)行速度。
A:目前Schema變更執(zhí)行速度按照最差效率估計(jì)約為10MB/s。可以根據(jù)這個(gè)速率來(lái)設(shè)置作業(yè)的超時(shí)時(shí)間。
Q:提交作業(yè)報(bào)錯(cuò)
Table xxx is not stable. ...
。A:Schema變更只有在表數(shù)據(jù)完整且未進(jìn)行均衡操作的狀態(tài)下才可以開(kāi)始。如果表的某些數(shù)據(jù)分片副本不完整,或者某些副本正在進(jìn)行均衡操作,則提交會(huì)被拒絕。
數(shù)據(jù)分片副本是否完整,可以通過(guò)以下命令查看:
ADMIN SHOW REPLICA STATUS FROM tbl WHERE STATUS != "OK";
如果有返回結(jié)果,則說(shuō)明有副本有問(wèn)題。通常系統(tǒng)會(huì)自動(dòng)修復(fù)這些問(wèn)題,也可以通過(guò)以下命令優(yōu)先修復(fù)這個(gè)表。
ADMIN REPAIR TABLE tbl1;
或者可以通過(guò)以下命令查看是否有正在運(yùn)行的均衡任務(wù):
SHOW PROC "/cluster_balance/pending_tablets";
可以等待均衡任務(wù)完成,或者通過(guò)以下命令臨時(shí)禁止均衡操作:
ADMIN SET FRONTEND CONFIG ("disable_balance" = "true");