PostgreSQL核心揭秘—元組結(jié)構(gòu)
概述
在PostgreSQL中,堆元組(Heap Tuple)是表中一行數(shù)據(jù)的內(nèi)部表示。每個堆元組都存儲在一個頁面(通常為8KB)內(nèi),并且由三個主要部分組成:HeapTupleHeaderData 結(jié)構(gòu)、空值位圖以及用戶數(shù)據(jù)。
詳細介紹
1. HeapTupleHeaderData 結(jié)構(gòu)
HeapTupleHeaderData 是元組頭部的數(shù)據(jù)結(jié)構(gòu),它包含了關(guān)于該元組的一些關(guān)鍵信息。這些信息包括事務相關(guān)的數(shù)據(jù)和一些標志位,用于多版本并發(fā)控制(MVCC)。
以下是其主要字段:
田 | 類型 | 長度 | 描述 |
t_xmin | 交易 ID | 4 字節(jié) | 插入 XID 圖章 |
t_xmax | 交易 ID | 4 字節(jié) | 刪除 XID 圖章 |
t_cid | CommandId | 4 字節(jié) | 插入和/或刪除 CID 圖章(與 t_xvac 疊加) |
t_xvac | 交易 ID | 4 字節(jié) | XID 用于 VACUUM 操作移動行版本 |
t_ctid | ItemPointerData (項目指針數(shù)據(jù)) | 6 字節(jié) | 此行版本或更新行版本的當前 TID |
t_infomask2 | uint16 | 2 字節(jié) | 屬性數(shù)量,以及各種標志位 |
t_infomask | uint16 | 2 字節(jié) | 各種標志位 |
t_hoff | uint8 | 1 字節(jié) | 用戶數(shù)據(jù)的偏移量 |
2. 空值位圖(Null Bitmap)
空值位圖是一個可選的部分,僅當表中有允許NULL值的列時存在。這個位圖用來標記哪些列的值是NULL。每個位對應一個列,如果某一位被設置,則表示相應的列是NULL。
3. 用戶數(shù)據(jù)(User Data)
用戶數(shù)據(jù)部分包含實際的字段值。這些值按照表定義中列的順序排列。對于固定長度的數(shù)據(jù)類型(如int4),直接存儲在用戶數(shù)據(jù)部分;對于可變長度的數(shù)據(jù)類型(如text、varchar),則會有一個長度前綴,隨后是實際的數(shù)據(jù)。
元組增、刪、改操作介紹
1. 增(INSERT)操作
假設元組是由 txid=99 的事務插入頁面中的,這時被插入元組的首部字段設置如下:
Tuple:
- t_xmin:設置為 99,因為此元組由 txid=99 的事務所插入。
- t_xmax:設置為 0,因為此元組尚未被刪除或更新。
- t_cid:設置為 0,因為此元組是由 txid=99 的事務所執(zhí)行的第一條命令插入的。
- t_ctid:設置為 (0,1),指向自身,因為這是該元組的最新版本。
2. 刪(DELETE)操作
圖片
假設接下來事務 txid=100 對元組進行了刪除操作。此時,刪除操作會設置如下:
Tuple(刪除后狀態(tài)):
- t_xmin:保持為 99,表示該元組的插入事務。
- t_xmax:設置為 100,因為此元組現(xiàn)在被 txid=100 的事務刪除。
- t_cid:設置為 0,因為刪除操作是由 txid=100 事務的第一條命令執(zhí)行的。
- t_ctid:保持為 (0,1),仍指向原元組。
死元組最終將從頁面中被移除。清除死元組的過程被稱為清理(VACUUM)過程
3. 改(UPDATE)操作
如果在 txid=101 的事務中,對該元組進行了更新操作。此時,更新操作會創(chuàng)建一個新的元組,且原元組保持不變。新元組的設置如下:
當執(zhí)行第一條UPDATE命令時,Tuple_1的t_xmax被設為txid 100,在邏輯上被刪除,然后Tuple_2被插入,接下來重寫Tuple_1的t_ctid以指向Tuple_2。Tuple_1和Tuple_2的頭部字段設置如下。
第一條 UPDATE 命令
邏輯刪除 Tuple_1:
- Tuple_1 的 t_xmax 被設置為 100(txid)。
- Tuple_1 的 t_ctid 從 (0,1) 改寫為 (0,2),指向新插入的元組。
Tuple_1 設置:
- t_xmax: 100、 t_ctid: (0,2)
插入新元組 Tuple_2:
- Tuple_2 的 t_xmin 被設置為 100(當前事務 txid)。
- t_xmax 設置為 0(尚未被刪除或更新)。
- t_cid 設置為 0(表示這是該事務的第一條操作)。
- t_ctid 設置為 (0,2)(指向自身)。
Tuple_2 設置:
- t_xmin: 100、t_xmax: 0、t_cid: 0、t_ctid: (0,2)
第二條 UPDATE 命令
邏輯刪除 Tuple_2:
- Tuple_2 的 t_xmax 被設置為 100(當前事務 txid)。
- Tuple_2 的 t_ctid 從 (0,2) 改寫為 (0,3),指向新插入的元組。
Tuple_2 設置:
- t_xmax: 100、t_ctid: (0,3)
插入新元組 Tuple_3:
- Tuple_3 的 t_xmin 被設置為 100(當前事務 txid)。
- t_xmax 設置為 0(尚未被刪除或更新)。
- t_cid 設置為 1(表示這是該事務的第二條操作)。
- t_ctid 設置為 (0,3)(指向自身)。
Tuple_3 設置:
- t_xmin: 100、t_xmax: 0、t_cid: 1、t_ctid: (0,3)
與刪除操作類似,如果txid=100的事務已經(jīng)提交,那么Tuple_1和Tuple_2就成了死元組,而如果txid=100的事務中止,Tuple_2和Tuple_3就成了死元組。
總結(jié)
在這個過程中,元組的狀態(tài)變化如下:
- 插入:新元組的字段由插入事務的 txid 決定。
- 刪除:刪除操作更新t_xmax,記錄刪除事務的txid。
- 更新:更新操作創(chuàng)建新的元組,新的 t_xmin 表示更新事務,并且t_cid和t_ctid 反映新的版本信息。