列存儲(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等)井氢,被多種查詢(xún)引擎支持(Hive、Impala、Drill等),并且它是語(yǔ)言和平臺(tái)無(wú)關(guān)的弄跌。Parquet最初是由Twitter和Cloudera(由于Impala的緣故)合作開(kāi)發(fā)完成并開(kāi)源,2015年5月從Apache的孵化器里畢業(yè)成為Apache頂級(jí)項(xiàng)目尝苇,最新的版本是1.8.1铛只。

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

查詢(xún)引擎: 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è)可以通過(guò)下圖來(lái)說(shuō)明非竿。數(shù)據(jù)從內(nèi)存到Parquet文件或者反過(guò)來(lái)的過(guò)程主要由以下三個(gè)部分組成:

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

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

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

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

  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格式,以及反過(guò)來(lái)把Parquet文件的數(shù)據(jù)反序列化成Pig Tuple铁蹈。

這里需要注意的是Avro, Thrift, Protocol Buffers都有他們自己的存儲(chǔ)格式宽闲,但是Parquet并沒(méi)有使用他們众眨,而是使用了自己在parquet-format項(xiàng)目里定義的存儲(chǔ)格式握牧。所以如果你的應(yīng)用使用了Avro等對(duì)象模型容诬,這些數(shù)據(jù)序列化到磁盤(pán)還是使用的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)入躲叼,基本上不需要支持單條記錄的增刪改操作,而查詢(xún)的時(shí)候大多數(shù)都是只使用部分列進(jìn)行過(guò)濾企巢、聚合枫慷,對(duì)少數(shù)列進(jìn)行計(jì)算(基本不需要select * from xx之類(lèi)的查詢(xún))。

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ǔ)可以大大提升這類(lèi)查詢(xún)的性能,較之于行是存儲(chǔ)笋婿,列式存儲(chǔ)能夠帶來(lái)這些優(yōu)化:

  1. 查詢(xún)的時(shí)候不需要掃描全部的數(shù)據(jù)誉裆,而只需要讀取每次查詢(xún)涉及的列,這樣可以將I/O消耗降低N倍缸濒,另外可以保存每一列的統(tǒng)計(jì)信息(min足丢、max、sum等)庇配,實(shí)現(xiàn)部分的謂詞下推斩跌。
  2. 由于每一列的成員都是同構(gòu)的,可以針對(duì)不同的數(shù)據(jù)類(lèi)型使用更高效的數(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è)問(wèn)題锻霎。

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類(lèi)型谆刨。

Parquet格式的數(shù)據(jù)類(lèi)型不需要復(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ǔ)通過(guò)將相同基本類(lèi)型(primitive type)的值存儲(chǔ)在一起來(lái)提供高效的編碼和解碼她我。為了用列存儲(chǔ)來(lái)存儲(chǔ)如上嵌套的數(shù)據(jù)結(jié)構(gòu)虹曙,我們需要將該schema用某種方式映射到一系列的列使我們能夠?qū)⒂涗泴?xiě)到列中并且能讀取成原來(lái)的嵌套的數(shù)據(jù)結(jié)構(gòu)。

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

上面的schema的樹(shù)結(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)自?xún)蓚€(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ù)類(lèi)型的特點(diǎn)是有些field(optional field 和 repeated field)可以是空的,也就是沒(méi)有定義捂齐。如果一個(gè)field是定義的蛮放,那么它的所有的父節(jié)點(diǎn)都是被定義的。從根節(jié)點(diǎn)開(kāi)始遍歷奠宜,當(dāng)某一個(gè)field的路徑上的節(jié)點(diǎn)開(kāi)始是空的時(shí)候我們記錄下當(dāng)前的深度作為這個(gè)field的Definition Level包颁。如果一個(gè)field的definition Level等于這個(gè)field的最大definition Level就說(shuō)明這個(gè)field是有數(shù)據(jù)的瞻想。對(duì)于required類(lèi)型的field必須是有定義的,所以這個(gè)Definition Level是不需要的娩嚼。在關(guān)系型數(shù)據(jù)中蘑险,optional類(lèi)型的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類(lèi)型的字段下“重復(fù)”出現(xiàn)的“重復(fù)”)英古。我們用深度0表示一個(gè)紀(jì)錄的開(kāi)頭(虛擬的根節(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類(lèi)型蕴掏,表示有且僅有一個(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’逗嫡,我們沒(méi)看到任何重復(fù)字段,也就是說(shuō)株依,重復(fù)深度是0驱证。當(dāng)我們遇到‘en’,字段Language重復(fù)了(在‘en-us’的路徑里已經(jīng)出現(xiàn)過(guò)一個(gè)Language)恋腕,所以重復(fù)深度是2.最終抹锄,當(dāng)我們遇到’en-gb‘,Name重復(fù)了(Name在前面‘en-us’和‘en’的路徑里已經(jīng)出現(xiàn)過(guò)一次吗坚,而此Name后Language只出現(xiàn)過(guò)一次祈远,沒(méi)有重復(fù)),所以重復(fù)深度是1商源。因此车份,r1中Code的值的重復(fù)深度是0、2牡彻、1.

要注意第二個(gè)Name在r1中沒(méi)有包含任何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的過(guò)程缎除。

對(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沒(méi)有phoneNumber,那么它的Definition Level就是1渐行。如果連contact都沒(méi)有轰坊,那么它的Definition Level就是0铸董。

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

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

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

serilizer.png

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

data in disk.png

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

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

  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沒(méi)有被定義豌习,所以創(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類(lèi)型的數(shù)據(jù)。對(duì)于這樣一個(gè)primitive類(lèi)型的數(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ǔ)開(kāi)銷(xiāo)呢?實(shí)際上這部分額外的存儲(chǔ)開(kāi)銷(xiāo)是可以忽略的凿宾。因?yàn)閷?duì)于一個(gè)schema來(lái)說(shuō)level都是有上限的矾屯,而且非repeated類(lèi)型的field不需要Repetition Level,required類(lèi)型的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ǔ)非嵌套類(lèi)型的時(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ù)的大小,通過(guò)該值和文件長(zhǎng)度可以計(jì)算出元數(shù)據(jù)的偏移量瞒大,文件的元數(shù)據(jù)中包括每一個(gè)行組的元數(shù)據(jù)信息和當(dāng)前文件的Schema信息螃征。除了文件中每一個(gè)行組的元數(shù)據(jù),每一頁(yè)的開(kāi)始都會(huì)存儲(chǔ)該頁(yè)的元數(shù)據(jù)糠赦,在Parquet中会傲,有三種類(lèi)型的頁(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ún)中需要的列,由于每一列的所有值都是連續(xù)存儲(chǔ)的会油,所以分區(qū)取出每一列的所有值就可以實(shí)現(xiàn)TableScan算子个粱,而避免掃描整個(gè)表文件內(nèi)容。

在Parquet中原生就支持映射下推翻翩,執(zhí)行查詢(xún)的時(shí)候可以通過(guò)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ù)之類(lèi)的查詢(xún)系統(tǒng)中最常用的優(yōu)化手段就是謂詞下推了钱雷,通過(guò)將一些過(guò)濾條件盡可能的在最底層執(zhí)行可以減少每一層交互的數(shù)據(jù)量,從而提升性能伴嗡,例如”select count(1) from A Join B on A.id = B.id where A.a > 10 and B.b < 100″SQL查詢(xún)中急波,在處理Join操作之前需要首先對(duì)A和B執(zhí)行TableScan操作,然后再進(jìn)行Join瘪校,再執(zhí)行過(guò)濾,最后計(jì)算聚合函數(shù)返回名段,但是如果把過(guò)濾條件A.a > 10和B.b < 100分別移到A表的TableScan和B表的TableScan的時(shí)候執(zhí)行阱扬,可以大大降低Join操作的輸入數(shù)據(jù)。

無(wú)論是行式存儲(chǔ)還是列式存儲(chǔ)伸辟,都可以在將過(guò)濾條件在讀取一條記錄之后執(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ù)。通過(guò)這些統(tǒng)計(jì)值和該列的過(guò)濾條件可以判斷該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 查詢(xún)

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ǔ)格式占用的空間相差并不大垂谢,查詢(xún)的結(jié)果顯示Parquet格式稍好于ORC格式,兩者在功能上也都有優(yōu)缺點(diǎn)疮茄,Parquet原生支持嵌套式數(shù)據(jù)結(jié)構(gòu)滥朱,而ORC對(duì)此支持的較差,這種復(fù)雜的Schema查詢(xún)也相對(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查詢(xún)的優(yōu)化方案,它已經(jīng)被多種查詢(xún)引擎原生支持躯畴,并且部分高性能引擎將其作為默認(rèn)的文件存儲(chǔ)格式民鼓。通過(guò)數(shù)據(jù)編碼和壓縮,以及映射下推和謂詞下推功能蓬抄,Parquet的性能也較之其它文件格式有所提升丰嘉,可以預(yù)見(jiàn),隨著數(shù)據(jù)模型的豐富和Ad hoc查詢(xún)的需求嚷缭,Parquet將會(huì)被更廣泛的使用饮亏。

5. 參考

FullStackPlan

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市阅爽,隨后出現(xiàn)的幾起案子路幸,更是在濱河造成了極大的恐慌,老刑警劉巖付翁,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件简肴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡百侧,警方通過(guò)查閱死者的電腦和手機(jī)砰识,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)佣渴,“玉大人辫狼,你說(shuō)我怎么就攤上這事」刍埃” “怎么了予借?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我灵迫,道長(zhǎng)秦叛,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任瀑粥,我火速辦了婚禮挣跋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狞换。我一直安慰自己避咆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布修噪。 她就那樣靜靜地躺著查库,像睡著了一般。 火紅的嫁衣襯著肌膚如雪黄琼。 梳的紋絲不亂的頭發(fā)上樊销,一...
    開(kāi)封第一講書(shū)人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音脏款,去河邊找鬼围苫。 笑死,一個(gè)胖子當(dāng)著我的面吹牛撤师,可吹牛的內(nèi)容都是我干的剂府。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼剃盾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼腺占!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起痒谴,我...
    開(kāi)封第一講書(shū)人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤湾笛,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后闰歪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蓖墅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年库倘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片论矾。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡教翩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贪壳,到底是詐尸還是另有隱情饱亿,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站彪笼,受9級(jí)特大地震影響钻注,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜配猫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一幅恋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泵肄,春花似錦捆交、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冯丙,卻和暖如春肉瓦,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背银还。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工风宁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蛹疯。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓戒财,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親捺弦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子饮寞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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