PostgreSQL t_bits计算方法
Posted PostgreSQLChina
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
以上是关于PostgreSQL t_bits计算方法的主要内容,如果未能解决你的问题,请参考以下文章