今天测试了下,有张大表字段需要扩充长度,即将 character varying(128) 扩大到 character varying(256),因为以前有Oracle 经验,类似的操作在Oracle 库里瞬间就能完成。因为只涉及到更改数据字典,不更改物理数据。下面来看下PG里的情况。
现象
查看表大小
1 |
select pg_size_pretty(pg_relation_size('log_foot_mark')); |
查看表结构
1 |
wapreader_log=> /d log_foot_mark |
扩字段长度
1 |
wapreader_log=> timing |
通常加字段的DDL是很快的,瞬间就能完成,为什么这次经历了十分钟,觉得很奇怪。那为什么PG里扩字段长度会花很长时间呢?难道在更改物理数据?带着这个疑问,做了以下测试,等下看结果。
测试
测试,创建一张表
1 |
create table test_1 (id integer ,remark varchar(32)); |
创建插入数据 function
1 |
CREATE OR REPLACE FUNCTION wapreader_log.fun_ins_test_1() |
插入 100 条数据
1 |
wapreader_log=> select wapreader_log.fun_ins_test_1(); |
查看数据,注意 ctid
1 |
wapreader_log=> select ctid,* from test_1 ; |
查看表大小
1 |
select pg_size_pretty(pg_relation_size('test_1')); |
更改字段长度
1 |
wapreader_log=> /d test_1 |
再次查看表的 ctid 和表大小
1 |
wapreader_log=> select ctid,* from test_1; |
发现表大小,ctid 均无变化,说明扩字段长度操作没有更改物理数据, 上述猜想是不成立的。后来我把这个问题发到一国外论坛上,上面有个回复我觉得解释得比较好:原文如下,就不翻译了
When you alter a table, PostgreSQL has to make sure the old version doesn’t go away in some cases, to allow rolling back the change if the server crashes before it’s committed and/or written to disk. For those reasons, what it actually does here even on what seems to be a trivial change is write out a whole new copy of the table somewhere else first. When that’s finished, it then swaps over to the new one. Note that when this happens, you’ll need enough disk space to hold both copies as well
There are some types of DDL changes that can be made without making a second copy of the table, but this is not one of them. For example, you can add a new column that defaults to NULL quickly. But adding a new column with a non-NULL default requires making a new copy instead.
总结
针对PG在扩字段长度时会扫描全表且时间较长的问题,总结以下经验
- 尽可能熟悉应用,对于不确定长度的 Character Types ,建议不指定长度。
- 对于Character较长的字段可以采用 text类型。
- Oracle 在给 varchar2 类型字段加长时,瞬间就能完成,在这点上,PG有着与Oracle 不同的方式;
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/236361.html