PostgreSQL表用户列最大个数
有些业务可能有这么个需求:需要增加用户列,即通过ALTER TABLE ... ADD...来添加用户列。那么PG/GP中是否会有列个数的限制呢?
它有1600列数的限制,并且没有方法去除掉这个限制。参见:
https://github.com/greenplum-db/gpdb/issues/15409
1)接着,我们创建一个1600列的表,进行下验证:
CREATE TABLE t1(id1 int,id2 int,id3 int,...,id1600 int);
2)然后,添加一列:
test=# alter table t1 add column co1601 int;
psql: ERROR: table can have at most 1600 columns
会报错提示,表最大有1600列。此时如果再添加新列怎么办?能否添加呢?
3)我们drop一列,然后再添加一列,是否可以?
test=# alter table t1 drop column co1600;
ALTER TABLE
test=# alter table t1 add column co1600 int;
psql: ERROR: table can have at most 1600 columns
显然,并不能通过这种方式添加新列。
4)在我们认知中,删除掉一列,不是就空出一个名额了么,咋还不给添加新列?
GP issues中对此进行了讨论:
https://github.com/greenplum-db/gpdb/issues/15459
显然,官方也没有计划对此行为进行修复。
Dropped columns are not removed from catalog. That's the behavior we inherit from upstream and avoids rewrite of table during drop column. So, no plans for now to modify the behavior. Understand it can be annoying. We are considering enhancing the behavior for Columnar tables to such reuse of dropped column for newly added columns. For now, closing the issue.
5)那么我们能否在代码中去掉这个限制,是否对其他地方有影响呢?
先看下,在什么地方限制的:
添加列的函数ATExecAddColumn,该函数对此进行限制的地方:
也就是宏MaxHeapAttributeNumber定义:#define MaxHeapAttributeNumber 1600
从上图可以看到限制的值来自pg_class系统表的relnatts字段。新增字段时,会对该字段进行更新:仍旧是ATExecAddColumn函数中:
Drop表时会对该字段进行更新吗?接着检查函数ATExecDropColumn,该函数将列删除后,并没有更新pg_class系统表的relnatts字段。OK,知道为什么删除一列,仍旧不能添加新列了吧。
6)如果,我们在ATExecDropColumn的地方将pg_class系统表进行更新,将该限制规避掉,是否可行?
需要知道,drop一列后,存于磁盘上表内的记录仍旧是完整列,也就是包含删除的列。在扫描时会将所有列值都扫描出来,投影时将删除的列去掉。修改后的后果:实际列超出1600,此时会对其他流程带来异常吗?
随便找下MaxHeapAttributeNumber使用的地方,比如toast_insert_or_update函数:
可以看到,有2个问题。如果修改这个限制的化,不是那么简单在drop列后更新pg_class系统表的relnatts字段值就可以的,需要仔细梳理代码,对其他流程受影响的地方都进行改造。当然,能否改造也需要打个问号,方便起见,还是对业务进行优化吧。