PostgreSQL記錄中的null值是如何存儲的


當向表中插入數據時,可以指定列的值為null。例如,有一張表t(i int,j int,k int),我們可以插入值(8,1,6),或將包含null值的(3,null,7)插入到表中。本文將探討PostgrSQL中是如何存儲null的一些技術細節。

PostgreSQL如何存儲null值的?

PostgreSQL中的一個元組被分成元組頭部分和數據部分。上面提到了向表t插入兩條數據的例子。這里,一幅圖片被用來拋出這個問題:在元組中null值是如何展示的?

 

如圖中所示,一個int類型的數據占據4個字節的空間,但是遇到null值時,數據庫該如何表示在3和7之間有個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'設計

‘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值。

結論

當記錄沒有任何空值時,t_bits不會存儲在記錄中。一旦存在空值,t_bits將存儲在元組中,以記錄所有列的空值狀態。表的刪除列被視為空列。因此,當表中有許多列時,請勿刪除列,否則將為每條記錄生成額外的t_bit,這將導致存儲膨脹。

 

 

 

https://www.highgo.ca/2020/10/20/the-way-to-store-null-value-in-pg-record/?utm_source=rss&utm_medium=rss&utm_campaign=the-way-to-store-null-value-in-pg-record


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM