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 时就得修改每行数据。

 

 

posted @ 2024-07-26 11:05  KINGBASE研究院  阅读(1)  评论(0编辑  收藏  举报