熟悉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
test=# insert into tab01 select generate_series(1,10000000),md5(random());
INSERT 0 10000000
test=# create index idx_tab01_id on tab01(id);
CREATE INDEX
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
#即使列上有索引,alter table操作也瞬间完成
test=# alter table tab01 alter column name type varchar(200);
ALTER TABLE
test=# select sys_relation_filepath('tab01');
sys_relation_filepath
-----------------------
base/13529/16408
可以看到,alter table 的过程瞬间完成(间接推断出不会去修改底层数据),表的底层存储文件也没变动。那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
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
test=# create table tab01(id integer,name varchar(100));
CREATE TABLE
test=# insert into tab01 select generate_series(1,1000000),null;
INSERT 0 1000000
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 时就得修改每行数据。
最后修改时间:2024-12-19 19:18:27
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




