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计算方法的主要内容,如果未能解决你的问题,请参考以下文章

10个JavaScript代码片段,使你更加容易前端开发。

10个JavaScript代码片段,使你更加容易前端开发。

使用从循环内的代码片段中提取的函数避免代码冗余/计算开销

计算光栅化片段的数量

将 Django/South/PostgreSQL 从按需要计算的汇总值迁移到数据库中维护的汇总值的正确方法是啥?

Postgresql 尝试使用 over() 计算总数的百分比。以前从未使用过 over() 但我读过这是正确的方法