SerializedPage 線上格式¶
Presto 使用 SerializedPage 二進位欄狀格式,在階段之間交換資料。
資料可以壓縮、加密,並包含校驗和。配置為標頭後接多個欄,然後是個別的欄。

標頭¶
標頭包含
欄位 |
大小 |
---|---|
列數 |
4 個位元組 |
編解碼器 |
1 個位元組 |
未壓縮大小 |
4 個位元組 |
大小 |
4 個位元組 |
校驗和 |
8 個位元組 |
編解碼器是一組標記,每個標記一個位元。 * 如果資料已壓縮,則設定第 1 個位元 * 如果資料已加密,則設定第 2 個位元 * 如果包含校驗和,則設定第 3 個位元
大小是標頭之後酬載的大小。如果資料未壓縮,則大小和未壓縮大小相同。如果資料已壓縮,則大小是壓縮後資料的大小,而未壓縮大小是壓縮前資料的大小。
校驗和是依指定順序計算在下列位元組上的 CRC32: * 標頭之後的資料 * 編解碼器 (1 個位元組) * 列數 (4 個位元組) * 未壓縮大小 (4 個位元組) 如果編解碼器未設定校驗和位元,則校驗和必須為零。
注意:欄數不是標頭的一部分。它儲存在標頭後緊接著的 4 個位元組中。

欄¶
每個欄都以標頭開始。後面接著資料。
欄標頭¶
欄標頭指定欄的編碼。
編碼名稱長度 - 4 個位元組
編碼名稱
支援的 Presto 類型編碼和對應為
編碼名稱 |
Presto 類型 |
---|---|
BYTE_ARRAY |
BOOLEAN、TINYINT、UNKNOWN |
SHORT_ARRAY |
SMALLINT |
INT_ARRAY |
INTEGER、REAL |
LONG_ARRAY |
BIGINT、DOUBLE、TIMESTAMP |
INT128_ARRAY |
未使用 |
VARIABLE_WIDTH |
VARCHAR、VARBINARY |
ARRAY |
ARRAY |
MAP |
MAP |
MAP_ELEMENT |
不適用 |
ROW |
ROW |
DICTIONARY |
不適用 |
RLE |
不適用 |
請參閱 presto-common/src/main/java/com/facebook/presto/common/block/BlockEncodingManager.java
例如,INTEGER 欄的標頭描述 INT_ARRAY 編碼。編碼名稱的長度為 9,因此,前 4 個位元組為 0 0 0 9。後面的 9 個位元組儲存 INT_ARRAY 字串。

Null 標記¶
所有欄都包含 1 個位元組的 has-nulls 標記。0 表示沒有 null。1 表示可能有 null。如果 has-nulls 位元組為 1,則會使用每個標記 1 個位元在後面的位元組中指定個別的 null 標記。0 表示值不是 null。1 表示值為 null。
Has-nulls 標記 - 1 個位元組
[選用] Null 標記 - 列數 / 8 個位元組;每個標記 1 個位元;位元依反向順序儲存在位元組中;每個位元組的第一個標記是高位元。
假設我們有 10 列,在以零為基底的列 1、4、6、7、9 中有 null。null 標記將以 3 個位元組表示。第一個位元組儲存 has-null 標記:1。第二個位元組儲存前 8 列的 null 標記。第三個位元組儲存最後 2 列的 null 標記。

XXX_ARRAY 編碼¶
BYTE_ARRAY、INT_ARRAY、SHORT_ARRAY、LONG_ARRAY 和 INT128_ARRAY 編碼的差異只在於每個值使用的位元組數。
資料配置為
列數 - 4 個位元組
Null 標記
值 - (列數 - null 數) * <每個值使用的位元組數> 位元組;僅表示非 null 值的列
每個值的位元組數為
編碼名稱 |
每個值使用的位元組數 |
---|---|
BYTE_ARRAY |
1 |
SHORT_ARRAY |
2 |
INT_ARRAY |
4 |
LONG_ARRAY |
8 |
INT128_ARRAY |
16 |
讓我們採用 Null 標記一節中的範例,並假設我們有一個整數欄,其中包含 10 列,而在以零為基底的列 1、4、6、7、9 中有 null。我們會有 4 個位元組儲存列數:10,後接 3 個位元組的 null 標記,後接 20 個位元組表示列 0、2、3、5、8 的 5 個非 null 整數值。

VARIABLE_WIDTH 編碼¶
列數 - 4 個位元組
位移 - 列數 * 4 個位元組;每個位移 4 個位元組
Null 標記
所有值中的位元組總數 - 4 個位元組
串聯的值
讓我們再次採用 Null 標記一節中的範例,並假設我們有一個字串欄,其中包含 10 列,而在以零為基底的列 1、4、6、7、9 中有 null。非 null 列將具有值:0 - Denali、2 - Reinier、3 - Whitney、5 - Bona、8 - Bear。我們會有 4 個位元組儲存列數:10,後接 40 個位元組的位移,後接 3 個位元組的 null 標記,後接 1 個位元組儲存所有字串的大小總計:28,後接串聯的字串值。請注意,我們具有所有列的位移,而不僅僅是非 null 列。

ARRAY 編碼¶
元素欄
列數 - 4 個位元組
位移 - (列數 + 1) * 4 個位元組;每個位移 4 個位元組
Null 標記
具有 10 列的陣列欄表示如下

MAP 編碼¶
索引鍵欄
值欄
雜湊表大小 (雜湊表中的 4 位元組區塊數) - 4 個位元組
[選用] 雜湊表:<雜湊表大小> * <4 個位元組>
列數 - 4 個位元組
位移 - (列數 + 1) * 4 個位元組;每個位移 4 個位元組
Null 標記
具有 10 列的地圖欄表示如下

ROW 編碼¶
欄位數 - 4 個位元組
每個欄位一個欄
列數 - 4 個位元組
位移 - (列數 + 1) * 4 個位元組;每個位移 4 個位元組
Null 標記
巢狀欄僅針對非 null 列序列化。在存在 null 列的情況下,巢狀欄的列號與頂層列號不符。位移指定巢狀欄的列號。
讓我們再次採用 Null 標記一節中的範例,並假設我們有一個 ROW(a, b, c, d) 類型的欄,其中包含 10 列,而在以零為基底的列 1、4、6、7、9 中有 null。巢狀欄只會有 5 列,而且位移將為:0、0、1、2、0、3、0、0、4、0。Null 列的位移為零。
注意:位移是冗餘資訊,因為它們可以從 null 標記重建。

DICTIONARY 編碼¶
列數 - 4 個位元組
字典值欄。此欄本身是一個序列化區塊,其編碼可以是本文件中提及的任何編碼。
索引 - 列數 * 4 個位元組;每個索引 4 個位元組
字典 ID - 24 個位元組
RLE 編碼¶
列數 - 4 個位元組
單列常數值欄
其他用途¶
SerializedPage 格式也用於指定從協調器傳送至工作節點的計畫片段中的常數值。在這種情況下,二進位表示會使用 base64 編碼轉換為 ASCII 字串。
例如,SELECT array[1, 23, 456] 查詢的計畫包含一個 Project 節點,其中 array[1, 23, 456] 值表示為 SerializedPage 格式的 base64 編碼二進位。
- Project[projectLocality = LOCAL] => [expr:array(integer)]
Estimates: {rows: 1 (51B), cpu: 51.00, memory: 0.00, network: 0.00}
expr := [Block: position count: 3; size: 92 bytes]
此外,當工作階段屬性 exchange_materialization_strategy 為 ALL,而且 temporary_table_storage_format 為 PAGEFILE 時,此格式會用於儲存中繼資料。