SerializedPage 線上格式

Presto 使用 SerializedPage 二進位欄狀格式,在階段之間交換資料。

資料可以壓縮、加密,並包含校驗和。配置為標頭後接多個欄,然後是個別的欄。

../_images/serialized-page-layout.png

標頭包含

欄位

大小

列數

4 個位元組

編解碼器

1 個位元組

未壓縮大小

4 個位元組

大小

4 個位元組

校驗和

8 個位元組

編解碼器是一組標記,每個標記一個位元。 * 如果資料已壓縮,則設定第 1 個位元 * 如果資料已加密,則設定第 2 個位元 * 如果包含校驗和,則設定第 3 個位元

大小是標頭之後酬載的大小。如果資料未壓縮,則大小和未壓縮大小相同。如果資料已壓縮,則大小是壓縮後資料的大小,而未壓縮大小是壓縮前資料的大小。

校驗和是依指定順序計算在下列位元組上的 CRC32: * 標頭之後的資料 * 編解碼器 (1 個位元組) * 列數 (4 個位元組) * 未壓縮大小 (4 個位元組) 如果編解碼器未設定校驗和位元,則校驗和必須為零。

注意:欄數不是標頭的一部分。它儲存在標頭後緊接著的 4 個位元組中。

../_images/serialized-page-header.png

每個欄都以標頭開始。後面接著資料。

欄標頭

欄標頭指定欄的編碼。

  • 編碼名稱長度 - 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 字串。

../_images/serialized-page-int-array.png

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 標記。

../_images/serialized-page-nulls.png

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 整數值。

../_images/serialized-page-int-column.png

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 列。

../_images/serialized-page-string-column.png

ARRAY 編碼

  • 元素欄

  • 列數 - 4 個位元組

  • 位移 - (列數 + 1) * 4 個位元組;每個位移 4 個位元組

  • Null 標記

具有 10 列的陣列欄表示如下

../_images/serialized-page-array-column.png

MAP 編碼

  • 索引鍵欄

  • 值欄

  • 雜湊表大小 (雜湊表中的 4 位元組區塊數) - 4 個位元組

  • [選用] 雜湊表:<雜湊表大小> * <4 個位元組>

  • 列數 - 4 個位元組

  • 位移 - (列數 + 1) * 4 個位元組;每個位移 4 個位元組

  • Null 標記

具有 10 列的地圖欄表示如下

../_images/serialized-page-map-column.png

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 標記重建。

../_images/serialized-page-row-column.png

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 時,此格式會用於儲存中繼資料。