列存儲(chǔ)格式Parquet淺析

Parquet調(diào)研報(bào)告

1. 概述

1.1 簡(jiǎn)介

Apache Parquet是Hadoop生態(tài)圈中一種新型列式存儲(chǔ)格式,它可以兼容Hadoop生態(tài)圈中大多數(shù)計(jì)算框架(Hadoop、Spark等),被多種查詢引擎支持(Hive、Impala、Drill等),并且它是語(yǔ)言和平臺(tái)無(wú)關(guān)的。Parquet最初是由Twitter和Cloudera(由于Impala的緣故)合作開發(fā)完成并開源,2015年5月從Apache的孵化器里畢業(yè)成為Apache頂級(jí)項(xiàng)目,最新的版本是1.8.1。

Parquet是語(yǔ)言無(wú)關(guān)的,而且不與任何一種數(shù)據(jù)處理框架綁定在一起,適配多種語(yǔ)言和組件,能夠與Parquet配合的組件有:

查詢引擎: Hive, Impala, Pig, Presto, Drill, Tajo, HAWQ, IBM Big SQL

計(jì)算框架: MapReduce, Spark, Cascading, Crunch, Scalding, Kite

數(shù)據(jù)模型: Avro, Thrift, Protocol Buffers, POJOs

那么Parquet是如何與這些組件協(xié)作的呢?這個(gè)可以通過下圖來(lái)說(shuō)明。數(shù)據(jù)從內(nèi)存到Parquet文件或者反過來(lái)的過程主要由以下三個(gè)部分組成:

  1. 存儲(chǔ)格式(storage format)

parquet-format項(xiàng)目定義了Parquet內(nèi)部的數(shù)據(jù)類型、存儲(chǔ)格式等。

  1. 對(duì)象模型轉(zhuǎn)換器(object model converters)

這部分功能由parquet-mr項(xiàng)目來(lái)實(shí)現(xiàn),主要完成外部對(duì)象模型與Parquet內(nèi)部數(shù)據(jù)類型的映射。

  1. 對(duì)象模型(object models)

對(duì)象模型可以簡(jiǎn)單理解為內(nèi)存中的數(shù)據(jù)表示,Avro, Thrift, Protocol Buffers, Hive SerDe, Pig Tuple, Spark SQL InternalRow等這些都是對(duì)象模型。Parquet也提供了一個(gè)example object model 幫助大家理解。

例如parquet-mr項(xiàng)目里的parquet-pig項(xiàng)目就是負(fù)責(zé)把內(nèi)存中的Pig Tuple序列化并按列存儲(chǔ)成Parquet格式,以及反過來(lái)把Parquet文件的數(shù)據(jù)反序列化成Pig Tuple。

這里需要注意的是Avro, Thrift, Protocol Buffers都有他們自己的存儲(chǔ)格式,但是Parquet并沒有使用他們,而是使用了自己在parquet-format項(xiàng)目里定義的存儲(chǔ)格式。所以如果你的應(yīng)用使用了Avro等對(duì)象模型,這些數(shù)據(jù)序列化到磁盤還是使用的parquet-mr定義的轉(zhuǎn)換器把他們轉(zhuǎn)換成Parquet自己的存儲(chǔ)格式。

module.png

1.2 列式存儲(chǔ)

列式存儲(chǔ),顧名思義就是按照列進(jìn)行存儲(chǔ)數(shù)據(jù),把某一列的數(shù)據(jù)連續(xù)的存儲(chǔ),每一行中的不同列的值離散分布。列式存儲(chǔ)技術(shù)并不新鮮,在關(guān)系數(shù)據(jù)庫(kù)中都已經(jīng)在使用,尤其是在針對(duì)OLAP場(chǎng)景下的數(shù)據(jù)存儲(chǔ),由于OLAP場(chǎng)景下的數(shù)據(jù)大部分情況下都是批量導(dǎo)入,基本上不需要支持單條記錄的增刪改操作,而查詢的時(shí)候大多數(shù)都是只使用部分列進(jìn)行過濾、聚合,對(duì)少數(shù)列進(jìn)行計(jì)算(基本不需要select * from xx之類的查詢)。

example:

以下這張表有A、B、C三個(gè)字段:

A B C
A1 B1 C1
A2 B2 C2
A3 B3 C3

行存儲(chǔ):

A1 B1 C1 A2 B2 C2 A3 B3 C3

列存儲(chǔ)

A1 A2 A3 B1 B2 B3 C1 C2 C3

列式存儲(chǔ)可以大大提升這類查詢的性能,較之于行是存儲(chǔ),列式存儲(chǔ)能夠帶來(lái)這些優(yōu)化:

  1. 查詢的時(shí)候不需要掃描全部的數(shù)據(jù),而只需要讀取每次查詢涉及的列,這樣可以將I/O消耗降低N倍,另外可以保存每一列的統(tǒng)計(jì)信息(min、max、sum等),實(shí)現(xiàn)部分的謂詞下推。
  2. 由于每一列的成員都是同構(gòu)的,可以針對(duì)不同的數(shù)據(jù)類型使用更高效的數(shù)據(jù)壓縮算法,進(jìn)一步減小I/O。
  3. 由于每一列的成員的同構(gòu)性,可以使用更加適合CPU pipeline的編碼方式,減小CPU的緩存失效。

2. Parquet詳解

2.1 數(shù)據(jù)模型

理解Parquet首先要理解這個(gè)列存儲(chǔ)格式的數(shù)據(jù)模型。我們以一個(gè)下面這樣的schema和數(shù)據(jù)為例來(lái)說(shuō)明這個(gè)問題。

message AddressBook {
 required string owner;
 repeated string ownerPhoneNumbers;
 repeated group contacts {
   required string name;
   optional string phoneNumber;
 }
}

這個(gè)schema中每條記錄表示一個(gè)人的AddressBook。有且只有一個(gè)owner,owner可以有0個(gè)或者多個(gè)ownerPhoneNumbers,owner可以有0個(gè)或者多個(gè)contacts。每個(gè)contact有且只有一個(gè)name,這個(gè)contact的phoneNumber可有可無(wú)。

每個(gè)schema的結(jié)構(gòu)是這樣的:根叫做message,message包含多個(gè)fields。每個(gè)field包含三個(gè)屬性:repetition, type, name。repetition可以是以下三種:required(出現(xiàn)1次),optional(出現(xiàn)0次或者1次),repeated(出現(xiàn)0次或者多次)。type可以是一個(gè)group或者一個(gè)primitive類型。

Parquet格式的數(shù)據(jù)類型不需要復(fù)雜的Map, List, Set等,而是使用repeated fields 和 groups來(lái)表示。例如List和Set可以被表示成一個(gè)repeated field,Map可以表示成一個(gè)包含有key-value 對(duì)的repeated group
,而且key是required的。

List(或Set)可以用repeated field來(lái)表示:

list.png

Map可以用包含key-value對(duì)且key是required的repeated group來(lái)表示:

map.png

2.2 列存儲(chǔ)格式

列存儲(chǔ)通過將相同基本類型(primitive type)的值存儲(chǔ)在一起來(lái)提供高效的編碼和解碼。為了用列存儲(chǔ)來(lái)存儲(chǔ)如上嵌套的數(shù)據(jù)結(jié)構(gòu),我們需要將該schema用某種方式映射到一系列的列使我們能夠?qū)⒂涗泴懙搅兄胁⑶夷茏x取成原來(lái)的嵌套的數(shù)據(jù)結(jié)構(gòu)。

在Parquet格式的存儲(chǔ)中,一個(gè)schema的樹結(jié)構(gòu)有幾個(gè)葉子節(jié)點(diǎn)(葉子節(jié)點(diǎn)都是primitive type),實(shí)際的存儲(chǔ)中就會(huì)有多少column。

上面的schema的樹結(jié)構(gòu)如圖所示:

tree struct.png

上面這個(gè)schema的數(shù)據(jù)存儲(chǔ)實(shí)際上有四個(gè)column,如下圖所示:

storage.png

只有字段值不能表達(dá)清楚記錄的結(jié)構(gòu)。給出一個(gè)repeated field的兩個(gè)值,我們不知道此值是按什么‘深度’被重復(fù)的(比如,這些值是來(lái)自兩個(gè)不同的記錄,還是相同的記錄中兩個(gè)重復(fù)的值)。同樣的,給出一個(gè)缺失的可選字段,我們不知道整個(gè)路徑有多少字段被顯示定義了。因此我們將介紹repetition level 和 definition level的概念。

example:

兩條嵌套的記錄和它們的schema:

two sample nested records and their schema

將上圖的兩條記錄用列存儲(chǔ)表示:

Column-striped representation

上面的例子主要是想讓大家對(duì)嵌套結(jié)構(gòu)的列式存儲(chǔ)有個(gè)直觀的印象,包括repetition level 和 definition level的應(yīng)用,接下來(lái)詳細(xì)介紹repetition level 和 definition level。

2.3 Definition levels

Definition level指明該列的路徑上多少個(gè)可選field被定義了。

嵌套數(shù)據(jù)類型的特點(diǎn)是有些field(optional field 和 repeated field)可以是空的,也就是沒有定義。如果一個(gè)field是定義的,那么它的所有的父節(jié)點(diǎn)都是被定義的。從根節(jié)點(diǎn)開始遍歷,當(dāng)某一個(gè)field的路徑上的節(jié)點(diǎn)開始是空的時(shí)候我們記錄下當(dāng)前的深度作為這個(gè)field的Definition Level。如果一個(gè)field的definition Level等于這個(gè)field的最大definition Level就說(shuō)明這個(gè)field是有數(shù)據(jù)的。對(duì)于required類型的field必須是有定義的,所以這個(gè)Definition Level是不需要的。在關(guān)系型數(shù)據(jù)中,optional類型的field被編碼成0表示空和1表示非空(或者反之)。

注:definition Level是該路徑上有定義的repeated field 和 optional field的個(gè)數(shù),不包括required field,因?yàn)閞equired field是必須有定義的。

再舉個(gè)簡(jiǎn)單的例子:

message ExampleDefinitionLevel {
  optional group a {
    required group b {
      optional string c;
    }
  }
}
example

因?yàn)閎是required field,所以第3行c的definition level為1而不是2(因?yàn)閎是required field,所有不需計(jì)算在內(nèi));第4行c的definition level為2而不是3(理由同上).

2.4 Repetition levels

Repetition level指明該值在路徑中哪個(gè)repeated field重復(fù)。

Repetition level是針對(duì)repeted field的。注意在圖2中的Code字段。可以看到它在r1出現(xiàn)了3次。‘en-us’、‘en’在第一個(gè)Name中,而‘en-gb’在第三個(gè)Name中。結(jié)合了圖2你肯定能理解我上一句話并知道‘en-us’、‘en’、‘en-gb’出現(xiàn)在r1中的具體位置,但是不看圖的話呢?怎么用文字,或者說(shuō)是一種定義、一種屬性、一個(gè)數(shù)值,詮釋清楚它們出現(xiàn)的位置?這就是重復(fù)深度這個(gè)概念的作用,它能用一個(gè)數(shù)字告訴我們?cè)诼窂街械氖裁粗貜?fù)字段,此值重復(fù)了,以此來(lái)確定此值的位置(注意,這里的重復(fù),特指在某個(gè)repeated類型的字段下“重復(fù)”出現(xiàn)的“重復(fù)”)。我們用深度0表示一個(gè)紀(jì)錄的開頭(虛擬的根節(jié)點(diǎn)),深度的計(jì)算忽略非重復(fù)字段(標(biāo)簽不是repeated的字段都不算在深度里)。所以在Name.Language.Code這個(gè)路徑中,包含兩個(gè)重復(fù)字段,Name和Language,如果在Name處重復(fù),重復(fù)深度為1(虛擬的根節(jié)點(diǎn)是0,下一級(jí)就是1),在Language處重復(fù)就是2,不可能在Code處重復(fù),它是required類型,表示有且僅有一個(gè);同樣的,在路徑Links.Forward中,Links是optional的,不參與深度計(jì)算(不可能重復(fù)),F(xiàn)orward是repeated的,因此只有在Forward處重復(fù)時(shí)重復(fù)深度為1。現(xiàn)在我們從上至下掃描紀(jì)錄r1。當(dāng)我們遇到’en-us’,我們沒看到任何重復(fù)字段,也就是說(shuō),重復(fù)深度是0。當(dāng)我們遇到‘en’,字段Language重復(fù)了(在‘en-us’的路徑里已經(jīng)出現(xiàn)過一個(gè)Language),所以重復(fù)深度是2.最終,當(dāng)我們遇到’en-gb‘,Name重復(fù)了(Name在前面‘en-us’和‘en’的路徑里已經(jīng)出現(xiàn)過一次,而此Name后Language只出現(xiàn)過一次,沒有重復(fù)),所以重復(fù)深度是1。因此,r1中Code的值的重復(fù)深度是0、2、1.

要注意第二個(gè)Name在r1中沒有包含任何Code值。為了確定‘en-gb’出現(xiàn)在第三個(gè)Name而不是第二個(gè),我們添加一個(gè)NULL值在‘en’和‘en-gb’之間(如圖3所示)。

2.5 Striping and assembly

下面用AddressBook的例子來(lái)說(shuō)明Striping和assembly的過程。

對(duì)于每個(gè)column的最大的Repetion Level和 Definition Level下圖所示。

max definition level and max repetition level

下面這樣兩條record:

AddressBook {
 owner: "Julien Le Dem",
 ownerPhoneNumbers: "555 123 4567",
 ownerPhoneNumbers: "555 666 1337",
 contacts: {
   name: "Dmitriy Ryaboy",
   phoneNumber: "555 987 6543",
 },
 contacts: {
   name: "Chris Aniszczyk"
 }
}

AddressBook {
 owner: "A. Nonymous"
}

以contacts.phoneNumber這一列為例,"555 987 6543"這個(gè)contacts.phoneNumber的Definition Level是最大Definition Level=2。而如果一個(gè)contact沒有phoneNumber,那么它的Definition Level就是1。如果連contact都沒有,那么它的Definition Level就是0。

下面我們拿掉其他三個(gè)column只看contacts.phoneNumber這個(gè)column,把上面的兩條record簡(jiǎn)化成下面的樣子:

AddressBook {
 contacts: {
   phoneNumber: "555 987 6543"
 }
 contacts: {
 }
}
AddressBook {
}

這兩條記錄的序列化過程如下圖所示:

serilizer.png

如果我們要把這個(gè)column寫到磁盤上,磁盤上會(huì)寫入這樣的數(shù)據(jù):

data in disk.png

注意:NULL實(shí)際上不會(huì)被存儲(chǔ),如果一個(gè)column value的Definition Level小于該column最大Definition Level的話,那么就表示這是一個(gè)空值。

下面是從磁盤上讀取數(shù)據(jù)并反序列化成AddressBook對(duì)象的過程:

  1. 讀取第一個(gè)三元組R=0, D=2, Value=”555 987 6543”

    R=0 表示是一個(gè)新的record,要根據(jù)schema創(chuàng)建一個(gè)新的nested record直到Definition Level=2。

    D=2 說(shuō)明Definition Level=Max Definition Level,那么這個(gè)Value就是contacts.phoneNumber這一列的值,賦值操作contacts.phoneNumber=”555 987 6543”。


  1. 讀取第二個(gè)三元組 R=1, D=1

    R=1 表示不是一個(gè)新的record,是上一個(gè)record中一個(gè)新的contacts。

    D=1 表示contacts定義了,但是contacts的下一個(gè)級(jí)別也就是phoneNumber沒有被定義,所以創(chuàng)建一個(gè)空的contacts。


  1. 讀取第三個(gè)三元組 R=0, D=0

    R=0 表示一個(gè)新的record,根據(jù)schema創(chuàng)建一個(gè)新的nested record直到Definition Level=0,也就是創(chuàng)建一個(gè)AddressBook根節(jié)點(diǎn)。

可以看出在Parquet列式存儲(chǔ)中,對(duì)于一個(gè)schema的所有葉子節(jié)點(diǎn)會(huì)被當(dāng)成column存儲(chǔ),而且葉子節(jié)點(diǎn)一定是primitive類型的數(shù)據(jù)。對(duì)于這樣一個(gè)primitive類型的數(shù)據(jù)會(huì)衍生出三個(gè)sub columns (R, D, Value),也就是從邏輯上看除了數(shù)據(jù)本身以外會(huì)存儲(chǔ)大量的Definition Level和Repetition Level。那么這些Definition Level和Repetition Level是否會(huì)帶來(lái)額外的存儲(chǔ)開銷呢?實(shí)際上這部分額外的存儲(chǔ)開銷是可以忽略的。因?yàn)閷?duì)于一個(gè)schema來(lái)說(shuō)level都是有上限的,而且非repeated類型的field不需要Repetition Level,required類型的field不需要Definition Level,也可以縮短這個(gè)上限。例如對(duì)于Twitter的7層嵌套的schema來(lái)說(shuō),只需要3個(gè)bits就可以表示這兩個(gè)Level了。

對(duì)于存儲(chǔ)關(guān)系型的record,record中的元素都是非空的(NOT NULL in SQL)。Repetion Level和Definition Level都是0,所以這兩個(gè)sub column就完全不需要存儲(chǔ)了。所以在存儲(chǔ)非嵌套類型的時(shí)候,Parquet格式也是一樣高效的。

2.6 文件格式

  • 行組(Row Group):按照行將數(shù)據(jù)物理上劃分為多個(gè)單元,每一個(gè)行組包含一定的行數(shù)。一個(gè)行組包含這個(gè)行組對(duì)應(yīng)的區(qū)間內(nèi)的所有列的列塊。

    官方建議:

    更大的行組意味著更大的列塊,使得能夠做更大的序列IO。我們建議設(shè)置更大的行組(512MB-1GB)。因?yàn)橐淮慰赡苄枰x取整個(gè)行組,所以我們想讓一個(gè)行組剛好在一個(gè)HDFS塊中。因此,HDFS塊的大小也需要被設(shè)得更大。一個(gè)最優(yōu)的讀設(shè)置是:1GB的行組,1GB的HDFS塊,1個(gè)HDFS塊放一個(gè)HDFS文件。

  • 列塊(Column Chunk):在一個(gè)行組中每一列保存在一個(gè)列塊中,行組中的所有列連續(xù)的存儲(chǔ)在這個(gè)行組文件中。不同的列塊可能使用不同的算法進(jìn)行壓縮。一個(gè)列塊由多個(gè)頁(yè)組成。

  • 頁(yè)(Page):每一個(gè)列塊劃分為多個(gè)頁(yè),頁(yè)是壓縮和編碼的單元,對(duì)數(shù)據(jù)模型來(lái)說(shuō)頁(yè)是透明的。在同一個(gè)列塊的不同頁(yè)可能使用不同的編碼方式。官方建議一個(gè)頁(yè)為8KB。

file format
metadata

上圖展示了一個(gè)Parquet文件的結(jié)構(gòu),一個(gè)文件中可以存儲(chǔ)多個(gè)行組,文件的首位都是該文件的Magic Code,用于校驗(yàn)它是否是一個(gè)Parquet文件,F(xiàn)ooter length存儲(chǔ)了文件元數(shù)據(jù)的大小,通過該值和文件長(zhǎng)度可以計(jì)算出元數(shù)據(jù)的偏移量,文件的元數(shù)據(jù)中包括每一個(gè)行組的元數(shù)據(jù)信息和當(dāng)前文件的Schema信息。除了文件中每一個(gè)行組的元數(shù)據(jù),每一頁(yè)的開始都會(huì)存儲(chǔ)該頁(yè)的元數(shù)據(jù),在Parquet中,有三種類型的頁(yè):數(shù)據(jù)頁(yè)、字典頁(yè)和索引頁(yè)。數(shù)據(jù)頁(yè)用于存儲(chǔ)當(dāng)前行組中該列的值,字典頁(yè)存儲(chǔ)該列值的編碼字典,每一個(gè)列塊中最多包含一個(gè)字典頁(yè),索引頁(yè)用來(lái)存儲(chǔ)當(dāng)前行組下該列的索引,目前Parquet中還不支持索引頁(yè),但是在后面的版本中增加。

2.7 映射下推(Project PushDown)

說(shuō)到列式存儲(chǔ)的優(yōu)勢(shì),映射下推是最突出的,它意味著在獲取表中原始數(shù)據(jù)時(shí)只需要掃描查詢中需要的列,由于每一列的所有值都是連續(xù)存儲(chǔ)的,所以分區(qū)取出每一列的所有值就可以實(shí)現(xiàn)TableScan算子,而避免掃描整個(gè)表文件內(nèi)容。

在Parquet中原生就支持映射下推,執(zhí)行查詢的時(shí)候可以通過Configuration傳遞需要讀取的列的信息,這些列必須是Schema的子集,映射每次會(huì)掃描一個(gè)Row Group的數(shù)據(jù),然后一次性得將該Row Group里所有需要的列的Cloumn Chunk都讀取到內(nèi)存中,每次讀取一個(gè)Row Group的數(shù)據(jù)能夠大大降低隨機(jī)讀的次數(shù),除此之外,Parquet在讀取的時(shí)候會(huì)考慮列是否連續(xù),如果某些需要的列是存儲(chǔ)位置是連續(xù)的,那么一次讀操作就可以把多個(gè)列的數(shù)據(jù)讀取到內(nèi)存。

2.8 謂詞下推(Predicate PushDown)

在數(shù)據(jù)庫(kù)之類的查詢系統(tǒng)中最常用的優(yōu)化手段就是謂詞下推了,通過將一些過濾條件盡可能的在最底層執(zhí)行可以減少每一層交互的數(shù)據(jù)量,從而提升性能,例如”select count(1) from A Join B on A.id = B.id where A.a > 10 and B.b < 100″SQL查詢中,在處理Join操作之前需要首先對(duì)A和B執(zhí)行TableScan操作,然后再進(jìn)行Join,再執(zhí)行過濾,最后計(jì)算聚合函數(shù)返回,但是如果把過濾條件A.a > 10和B.b < 100分別移到A表的TableScan和B表的TableScan的時(shí)候執(zhí)行,可以大大降低Join操作的輸入數(shù)據(jù)。

無(wú)論是行式存儲(chǔ)還是列式存儲(chǔ),都可以在將過濾條件在讀取一條記錄之后執(zhí)行以判斷該記錄是否需要返回給調(diào)用者,在Parquet做了更進(jìn)一步的優(yōu)化,優(yōu)化的方法時(shí)對(duì)每一個(gè)Row Group的每一個(gè)Column Chunk在存儲(chǔ)的時(shí)候都計(jì)算對(duì)應(yīng)的統(tǒng)計(jì)信息,包括該Column Chunk的最大值、最小值和空值個(gè)數(shù)。通過這些統(tǒng)計(jì)值和該列的過濾條件可以判斷該Row Group是否需要掃描。另外Parquet未來(lái)還會(huì)增加諸如Bloom Filter和Index等優(yōu)化數(shù)據(jù),更加有效的完成謂詞下推。

3. 性能

3.1 壓縮

compression

上圖是展示了使用不同格式存儲(chǔ)TPC-H和TPC-DS數(shù)據(jù)集中兩個(gè)表數(shù)據(jù)的文件大小對(duì)比,可以看出Parquet較之于其他的二進(jìn)制文件存儲(chǔ)格式能夠更有效的利用存儲(chǔ)空間,而新版本的Parquet(2.0版本)使用了更加高效的頁(yè)存儲(chǔ)方式,進(jìn)一步的提升存儲(chǔ)空間。

3.2 查詢

query1

上圖展示了Twitter在Impala中使用不同格式文件執(zhí)行TPC-DS基準(zhǔn)測(cè)試的結(jié)果,測(cè)試結(jié)果可以看出Parquet較之于其他的行式存儲(chǔ)格式有較明顯的性能提升。

query2

上圖展示了criteo公司在Hive中使用ORC和Parquet兩種列式存儲(chǔ)格式執(zhí)行TPC-DS基準(zhǔn)測(cè)試的結(jié)果,測(cè)試結(jié)果可以看出在數(shù)據(jù)存儲(chǔ)方面,兩種存儲(chǔ)格式在都是用snappy壓縮的情況下量中存儲(chǔ)格式占用的空間相差并不大,查詢的結(jié)果顯示Parquet格式稍好于ORC格式,兩者在功能上也都有優(yōu)缺點(diǎn),Parquet原生支持嵌套式數(shù)據(jù)結(jié)構(gòu),而ORC對(duì)此支持的較差,這種復(fù)雜的Schema查詢也相對(duì)較差;而Parquet不支持?jǐn)?shù)據(jù)的修改和ACID,但是ORC對(duì)此提供支持,但是在OLAP環(huán)境下很少會(huì)對(duì)單條數(shù)據(jù)修改,更多的則是批量導(dǎo)入。

4. 總結(jié)

本文介紹了一種支持嵌套數(shù)據(jù)模型對(duì)的列式存儲(chǔ)格式Parquet,作為大數(shù)據(jù)系統(tǒng)中OLAP查詢的優(yōu)化方案,它已經(jīng)被多種查詢引擎原生支持,并且部分高性能引擎將其作為默認(rèn)的文件存儲(chǔ)格式。通過數(shù)據(jù)編碼和壓縮,以及映射下推和謂詞下推功能,Parquet的性能也較之其它文件格式有所提升,可以預(yù)見,隨著數(shù)據(jù)模型的豐富和Ad hoc查詢的需求,Parquet將會(huì)被更廣泛的使用。

5. 參考

FullStackPlan

歡迎關(guān)注公眾號(hào): FullStackPlan 獲取更多干貨哦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評(píng)論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容