
PostgreSQL如何存儲null值的?
PostgreSQL存儲null值的方法
使用pageinspact工具來觀察null是如何存儲的。執行下面的測試:
postgres=# create table t(i int, j int, k int);
CREATE TABLE
postgres=# insert into t values(8,1,6);
INSERT 0 1
postgres=# insert into t values(3,NULL,7);
INSERT 0 1
postgres=# insert into t values(4,9,2);
INSERT 0 1
postgres=# select lp,t_infomask,t_bits,t_data from heap_page_items(get_raw_page('t', 0));
lp | t_infomask | t_bits | t_data
----+------------+----------+----------------------------
1 | 2048 | | \x080000000100000006000000
2 | 2049 | 10100000 | \x0300000007000000
3 | 2048 | | \x040000000900000002000000
(3 rows)
postgres=#
可以看到,null值沒有在元組的數據部分標記出來。

同時,可以看到帶有null值的第二條記錄的't_infomask'和’t_bits‘的值與第一條和第三條是不一致的。因此,這可能就是如何讀取null值的秘密所在。
‘t_bits’是一個uint8的數組,當元組中沒有null值的時候,t_bits可以被認為是空的,當元組有null值的列時,t_bits使用一個位(bit)來表示一個列是否為null。
postgres=# create table t0(i1 int,i2 int,i3 int,i4 int,i5 int,i6 int,
postgres(# i7 int,i8 int,i9 int,i10 int,i11 int,i12 int
postgres(# );
CREATE TABLE
postgres=# insert into t0 values(1,2,3,4,5,6,7,8,9,10,NULL,12);
INSERT 0 1
postgres=# insert into t0 values(1,2,3,4,5,6,7,8,9,NULL,NULL,12);
INSERT 0 1
postgres=# insert into t0 values(1,2,3,4,5,6,7,8,NULL,NULL,NULL,12);
INSERT 0 1
postgres=# insert into t0 values(1,2,3,4,5,6,7,8,9,10,11,12);
INSERT 0 1
postgres=#
postgres=# select lp,t_infomask,t_bits from heap_page_items(get_raw_page('t0', 0));
lp | t_infomask | t_bits
----+------------+------------------
1 | 2049 | 1111111111010000
2 | 2049 | 1111111110010000
3 | 2049 | 1111111100010000
4 | 2048 |
(4 rows)
postgres=#
上面的腳本會創建一個表t0,共有12個列,然后插入幾條元組,執行pageinspect工具查詢研究元組。注意看元組的t_bits值:

可以得出結論:
·在t_bits中,尚未使用的標記為是0
·1表示對應的列是非空的(not null),否則就是null
在PostgreSQL中,表的列被刪除后,這個列的數據結構會被保留在目錄中,但是對用戶是不可見的。完成下面的測試:
postgres=# alter table t0 drop column i1;
ALTER TABLE
postgres=# insert into t0 values(2,3,4,5,6,7,8,9,10,11,12);
INSERT 0 1
postgres=# select lp,t_infomask,t_bits from heap_page_items(get_raw_page('t0', 0));
lp | t_infomask | t_bits
----+------------+------------------
1 | 2049 | 1111111111010000
2 | 2049 | 1111111110010000
3 | 2049 | 1111111100010000
4 | 2048 |
5 | 2049 | 0111111111110000
(5 rows)
postgres=#
在這個測試中,我們刪除了表t0的列'i1'並插入一個不含有null值的記錄。使用pageinspact工具,我們可以發現插入的不含有null值的數據(lp=5)。被刪除的列的t_bits值顯示其也被認為是null值。

結論

