KingbaseES 如何做到增加非空列而无需重写表
熟悉Oracle的DBA就知道,Oracle早期11g版本在增加非空列(default or not null default)时,需要回写表,也就是需要针对每一行的记录进行修改。Oracle12c 开始,修改或增加非空字段都无需更新数据表。对于KingbaseES ,增加非空列同样不需要更新数据,alter table操作可以快速返回,将对业务的影响降低到最小。KingbaseES是如何做到的?我们来看实际例子。
一、测试过程
test=# create table tab01(id integer,name varchar(100)); CREATE TABLE 时间:2.498 ms test=# insert into tab01 select generate_series(1,10000000),md5(random()); INSERT 0 10000000 时间:49114.272 ms (00:49.114) test=# create index idx_tab01_id on tab01(id); CREATE INDEX 时间:12344.101 ms (00:12.344) test=# select sys_relation_filepath('tab01'); sys_relation_filepath ----------------------- base/13529/16408 --千万级数据,alter操作瞬间完成
test=# ALTER TABLE tab01 add city varchar2(50) default 'FuZhou' not null; ALTER TABLE 时间:2.427 ms test=# select sys_relation_filepath('tab01'); sys_relation_filepath ----------------------- base/13529/16408 test=# create index idx_tab01_name on tab01(name); CREATE INDEX 时间:132274.806 ms (02:12.275)
--即使列上有索引,alter table操作也瞬间完成 test=# alter table tab01 alter column name type varchar(200); ALTER TABLE 时间:3.506 ms test=# select sys_relation_filepath('tab01'); sys_relation_filepath ----------------------- base/13529/16408
可以看到,修改的过程瞬间完成(间接推断出不会去修改底层数据),表的底层存储文件也没变动。那KingbaseES是如何做到这点的?
二、机制分析
KingbaseES 之所以能做到无需修改底层数据,是由于系统表 sys_attribute 有两个字段:atthasmissing 和 attmissingval。我们来看具体的值:
test=# select attname, attmissingval, atthasmissing from pg_attribute where attnum > 0 and attrelid = 'tab01'::regclass; attname | attmissingval | atthasmissing ---------+---------------+--------------- id | | f name | | f city | {FuZhou} | t
可以看到新增加的非空列 atthasmissing=true,也就是告诉查询执行器,该非空列在数据行有部分没数据,而如果没有数据,就用attmissingval值替代。
如果表重整,则数据会写回行,不再需要 atthasmissing 和 attmissingval 。
test=# vacuum full tab01; VACUUM 时间:148090.441 ms (02:28.090) test=# select attname, attmissingval, atthasmissing from pg_attribute where attnum > 0 and attrelid = 'tab01'::regclass; attname | attmissingval | atthasmissing ---------+---------------+--------------- id | | f name | | f city | | f (3 行记录)
可以看到,vacuum full 后,atthasmissing 和 attmissingval 数据已经没有了,因为数据已写回每行。
三、需要重写表的场景
增加的列默认值通过volatile类型函数生成。由于volatile函数的特性,需要在增加列时就执行,也就是必须立即修改行数据。来看实际例子:
test=# drop table tab01; DROP TABLE 时间:135.531 ms test=# create table tab01(id integer,name varchar(100)); CREATE TABLE 时间:2.412 ms test=# insert into tab01 select generate_series(1,1000000),null; INSERT 0 1000000 时间:1174.976 ms (00:01.175) test=# ALTER TABLE tab01 add city varchar2(50) default random() not null; ALTER TABLE 时间:1106.471 ms (00:01.106) test=# select attname, attmissingval, atthasmissing from pg_attribute where attnum > 0 and attrelid = 'tab01'::regclass; attname | attmissingval | atthasmissing ---------+---------------+--------------- id | | f name | | f city | | f (3 行记录)
可以看到,如果default 值是通过 random (volatile 类型函数)函数生成,则在alter table 时就得修改每行数据。
KINGBASE研究院