PostgreSQL t_bits计算方法

在PostgreSQL的page头部使用t_bits来表示null值的列。
定义如下:

bits8		t_bits[FLEXIBLE_ARRAY_MEMBER];	/* bitmap of NULLs */

之前看的时候以为其长度就是8个bit位,用1个字节来存储。今天和别人聊的时候才发现如果只是8个bit位那完全不够啊,pg中表最多允许1600列,那不是应该需要1600位?

于是建个70列的表测试下看看:

bill@bill=>create table t1(
bill(# c1 int, c2 int, c3 int, c4 int, c5 int,
bill(# c6 int, c7 int, c8 int, c9 int, c10 int,
bill(# c11 int, c12 int, c13 int, c14 int, c15 int,
bill(# c16 int, c17 int, c18 int, c19 int, c20 int,
bill(# c21 int, c22 int, c23 int, c24 int, c25 int,
bill(# c26 int, c27 int, c28 int, c29 int, c30 int,
bill(# c31 int, c32 int, c33 int, c34 int, c35 int,
bill(# c36 int, c37 int, c38 int, c39 int, c40 int,
bill(# c41 int, c42 int, c43 int, c44 int, c45 int,
bill(# c46 int, c47 int, c48 int, c49 int, c50 int,
bill(# c51 int, c52 int, c53 int, c54 int, c55 int,
bill(# c56 int, c57 int, c58 int, c59 int, c60 int,
bill(# c61 int, c62 int, c63 int, c64 int, c65 int,
bill(# c66 int, c67 int, c68 int, c69 int, c70 int
bill(# );
CREATE TABLE

插入数据查看t_bits:

bill@bill=>insert into t1(c1,c2) values(1,1);
INSERT 0 1
bill@bill=>select * from heap_page_items(get_raw_page('t1',0));
 lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff |                                  t_bits
                             | t_oid |       t_data
----+--------+----------+--------+--------+--------+----------+--------+-------------+------------+--------+---------------------------------------------
-----------------------------+-------+--------------------
  1 |   8152 |        1 |     40 |   3974 |      0 |        0 | (0,1)  |          70 |       2049 |     32 | 11000000000000000000000000000000000000000000
0000000000000000000000000000 |       | \x0100000001000000
(1 row)

可以看到t_bits总共72位,前两位为1刚好表示c1和c2列不为空。那看来t_bits的大小确实不是8个bit位就能搞定的,那是怎么计算的呢?

仔细观察发现,t_bits[FLEXIBLE_ARRAY_MEMBER]其实是使用了C语言中的FLEXIBLE_ARRAY_MEMBER,即弹性数组。这个之前确实也不太清楚,查了下资料什么是弹性数组呢?

其形式如下:

struct Foo {    int a;    char b[]; // 有时也写成 char b[0];};

如果不使用弹性数组,那么我们需要写成:

struct Foo {    int a;};struct Foo *foo = malloc(sizeof(struct Foo) + 128);char *b = (char *)foo + sizeof(struct Foo);

这样就能很明显的看出,弹性数组只是一个语法糖,它在结构体最后增加一个成员变量,让我们可以使用foo->b这种方式,直接访问结构体之后的内存。事实上,你如果自己计算偏移量,也可以到达一样的效果。

而这里的t_bits是其实也是这样,其长度是要在使用时去计算偏移量的。

#define BITMAPLEN(NATTS)	(((int)(NATTS) + 7) / 8)

if (hasnull)
		len += BITMAPLEN(numberOfAttributes);

可以看到t_bits的长度其实是和列的个数有关的,这也是为什么定义为bits8 t_bits[FLEXIBLE_ARRAY_MEMBER]的原因了。

参考链接:
https://zhuanlan.zhihu.com/p/93811576
include/access/htup_details.h
backend/access/common/heaptuple.c

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值