Hive從0.11版本開(kāi)始提供了ORC的文件格式,ORC文件不僅僅是一種列式文件存儲(chǔ)格式狂打,最重要的是有著很高的壓縮比敌呈,并且對(duì)于MapReduce來(lái)說(shuō)是可切分(Split)的。因此颓哮,在Hive中使用ORC作為表的文件存儲(chǔ)格式,不僅可以很大程度的節(jié)省HDFS存儲(chǔ)資源鸵荠,而且對(duì)數(shù)據(jù)的查詢(xún)和處理性能有著非常大的提升冕茅,因?yàn)镺RC較其他文件格式壓縮比高,查詢(xún)?nèi)蝿?wù)的輸入數(shù)據(jù)量減少,使用的Task也就減少了姨伤。
ORC文件是自描述的哨坪,它的元數(shù)據(jù)使用Protocol Buffers序列化,并且文件中的數(shù)據(jù)盡可能的壓縮以降低存儲(chǔ)空間的消耗姜挺,目前也被Spark SQL齿税、Presto等查詢(xún)引擎支持彼硫,但是Impala對(duì)于ORC目前沒(méi)有支持炊豪,仍然使用Parquet作為主要的列式存儲(chǔ)格式。2015年ORC項(xiàng)目被Apache項(xiàng)目基金會(huì)提升為Apache頂級(jí)項(xiàng)目拧篮。
例如词渤,與RCFile格式相比,ORC文件格式具有許多優(yōu)點(diǎn)串绩,例如:
- 一個(gè)文件作為每個(gè)任務(wù)的輸出缺虐,這減少了NameNode的負(fù)載
- 支持復(fù)雜的數(shù)據(jù)結(jié)構(gòu),Hive類(lèi)型支持包括datetime礁凡,decimal和復(fù)雜類(lèi)型(struct高氮,list,map和union)
- 三級(jí)索引顷牌,存儲(chǔ)在文件中的輕量級(jí)索引剪芍,能過(guò)濾掉沒(méi)在查找范圍內(nèi)的數(shù)據(jù)塊,快速查詢(xún)到滿(mǎn)足條件的數(shù)據(jù)
- 基于數(shù)據(jù)類(lèi)型的塊模式壓縮窟蓝,整數(shù)列的行程編碼罪裹,字符串列的字典編碼,減少了讀或?qū)懰璧臄?shù)據(jù)量
- 分割的數(shù)據(jù)塊运挫,使用單獨(dú)的RecordReaders并發(fā)讀取同一文件
由于ORC普遍應(yīng)用于Apache大數(shù)據(jù)生態(tài)状共,了解其原理,有助于hive和presto查詢(xún)優(yōu)化谁帕。
列式存儲(chǔ)
列式存儲(chǔ)可以提升OLAP查詢(xún)查詢(xún)性能峡继,但是它是如何做到的呢?這就要從列式存儲(chǔ)的原理說(shuō)起匈挖,從圖1中可以看到鬓椭,相對(duì)于關(guān)系數(shù)據(jù)庫(kù)中通常使用的行式存儲(chǔ),在使用列式存儲(chǔ)時(shí)每一列的所有元素都是順序存儲(chǔ)的关划。由此特點(diǎn)可以給查詢(xún)帶來(lái)如下的優(yōu)化:
1)查詢(xún)的時(shí)候不需要掃描全部的數(shù)據(jù)小染,而只需要讀取每次查詢(xún)涉及的列,這樣可以將I/O消耗降低N倍贮折,另外可以保存每一列的統(tǒng)計(jì)信息(min裤翩、max、sum,字符類(lèi)型數(shù)據(jù)長(zhǎng)度等)踊赠,實(shí)現(xiàn)部分的謂詞下推呵扛。
2)由于每一列的成員都是同構(gòu)的,可以針對(duì)不同的數(shù)據(jù)類(lèi)型使用更高效的數(shù)據(jù)壓縮算法筐带,進(jìn)一步減小I/O今穿。
3)由于每一列的成員的同構(gòu)性,可以使用更加適合CPU pipeline的編碼方式伦籍,減小CPU的緩存失效蓝晒。
文件結(jié)構(gòu)
從下圖可以看到ORC文件結(jié)構(gòu)
ORC文件的元數(shù)據(jù)一個(gè)ORC文件會(huì)被分成多個(gè)stripe,而且文件的元數(shù)據(jù)中有每個(gè)字段的統(tǒng)計(jì)信息(min/max帖鸦,sum芝薇,hasNull等等),這就為ORC的查詢(xún)優(yōu)化做好了基礎(chǔ)準(zhǔn)備作儿。
整個(gè)文件從下往上分成幾個(gè)部分:
1)Postscript: 提供了解釋文件其余部分的必要信息洛二,包括文件的頁(yè)腳和元數(shù)據(jù)部分的長(zhǎng)度,文件的版本以及使用的常規(guī)壓縮類(lèi)型(例如攻锰,none晾嘶,zlib,LZO娶吞,LZ4垒迂,ZSTD或snappy)
2)File Footer: 包含文件正文的布局,類(lèi)型架構(gòu)信息寝志,行數(shù)以及每個(gè)列的統(tǒng)計(jì)信息娇斑。
3)Stripe條帶數(shù)據(jù)塊:文件正文分為條帶。每個(gè)條帶都是自包含的材部,只能使用自己的字節(jié)與文件的Footer和Postscript結(jié)合使用毫缆。每個(gè)條帶僅包含整行,因此行不會(huì)跨越條帶邊界乐导。Stripes有三個(gè)部分:條帶中行的一組索引苦丁,數(shù)據(jù)本身和條帶頁(yè)腳。索引和數(shù)據(jù)部分都按列分割物臂,因此只需要讀取所需列的數(shù)據(jù)旺拉。
4)列統(tǒng)計(jì):列統(tǒng)計(jì)信息的目標(biāo)是,對(duì)于每個(gè)列棵磷,編寫(xiě)器記錄計(jì)數(shù)并根據(jù)其他有用字段的類(lèi)型進(jìn)行記錄蛾狗。對(duì)于大多數(shù)原始類(lèi)型,它記錄最小值和最大值; 對(duì)于數(shù)字類(lèi)型仪媒,它還存儲(chǔ)總和沉桌。從Hive 1.1.0開(kāi)始,列統(tǒng)計(jì)信息還將通過(guò)設(shè)置hasNull標(biāo)志來(lái)記錄行組中是否存在任何空值。ORC的謂詞下推使用hasNull標(biāo)志來(lái)更好地回答'IS NULL'查詢(xún)留凭。真實(shí)列數(shù)據(jù)塊佃扼,其中又分為Index data( 記錄每列的索引信息),Raw Data(記錄原始數(shù)據(jù))蔼夜,Stripe Footer(記錄每列的統(tǒng)計(jì)信息兼耀,min/max/sum等)。
Stripe在默認(rèn)情況下64MB求冷。文件中的條帶彼此獨(dú)立瘤运,形成分布式工作的自然單元。在每個(gè)條帶中遵倦,列彼此分開(kāi)尽超,因此Reader只能讀取所需的列官撼。
三級(jí)索引
ORC在每個(gè)文件中提供三級(jí)索引:
文件級(jí)別 - 有關(guān)整個(gè)文件中每列中的值的統(tǒng)計(jì)信息
stripe條帶級(jí)別 - 有關(guān)每個(gè)條帶的每列中的值的統(tǒng)計(jì)信息
行級(jí)別 (行組)- 條帶中每組10,000行(默認(rèn)值)的每列值的統(tǒng)計(jì)信息
文件和條帶級(jí)別列統(tǒng)計(jì)信息位于文件頁(yè)腳中梧躺,因此可以輕松訪(fǎng)問(wèn)它們以確定是否需要讀取文件的其余部分。行級(jí)索引包括每個(gè)行組的列統(tǒng)計(jì)信息和搜索行組開(kāi)頭的位置傲绣。
列統(tǒng)計(jì)信息始終包含值的計(jì)數(shù)以及是否存在空值掠哥。大多數(shù)其他原始類(lèi)型包括最小值和最大值,對(duì)于數(shù)字類(lèi)型秃诵,則包括總和续搀。從Hive 1.2開(kāi)始,索引可以包括bloom過(guò)濾器菠净,它提供了更具選擇性的過(guò)濾器禁舷。
索引工作原理
1)假如我的查詢(xún)過(guò)濾條件為WHERE id = 0;在Map Task讀到一個(gè)ORC文件時(shí),首先從文件的統(tǒng)計(jì)信息(一級(jí)索引)中看看id字段的min/max值毅往,如果0不包含在內(nèi)牵咙,那么跳過(guò)該文件
2)如果在這個(gè)文件中,那么繼續(xù)查看每個(gè)stripe中id字段的min/max值(二級(jí)索引)攀唯,如果0不包含在內(nèi)洁桌,那么跳過(guò)在stripe
3)如果在該stripe中,則繼續(xù)匹配行組中的min/max值(三級(jí)索引)侯嘀,如果0不包含在內(nèi)另凌,那么跳過(guò)該行組。如果0包含在內(nèi)min和max范圍內(nèi)戒幔,則利用布隆過(guò)濾器再次判斷是否一定不在內(nèi)吠谢,不在內(nèi)則繼續(xù)跳過(guò)該行組。
這種索引通常用于數(shù)值型字段的查詢(xún)過(guò)濾優(yōu)化上诗茎。
布隆過(guò)濾器
本質(zhì)上布隆過(guò)濾器是一種數(shù)據(jù)結(jié)構(gòu)工坊,比較巧妙的概率型數(shù)據(jù)結(jié)構(gòu)(probabilistic data structure),布隆過(guò)濾器是一個(gè) bit 向量或者說(shuō) bit 數(shù)組和一組hash函數(shù)組成。特點(diǎn)是高效地插入和查詢(xún)栅组,可以用來(lái)告訴你 “某樣?xùn)|西一定不存在或者可能存在”雀瓢。
布隆過(guò)濾器可以應(yīng)用在各種類(lèi)型字段上,包括字符串和二進(jìn)制玉掸。
謂詞下推
謂詞下推(predicate pushdown)屬于邏輯優(yōu)化刃麸。優(yōu)化器可以將謂詞過(guò)濾下推到數(shù)據(jù)源,從而使物理執(zhí)行跳過(guò)無(wú)關(guān)數(shù)據(jù)司浪。在邏輯層面可以理解為利用where 條件中的過(guò)濾條件將無(wú)用的數(shù)據(jù)進(jìn)行篩選掉最終得到需要的行列泊业。
在ORC中表現(xiàn)為:
1)列式存儲(chǔ)可以容易過(guò)濾掉不需要的列數(shù)據(jù)
2)利用三級(jí)索引中的統(tǒng)計(jì)信息可以跳過(guò)不需要的文件,條帶塊或行組
Hive建表優(yōu)化
Hive中建表使用ORC存儲(chǔ)格式時(shí)啊易,ORC默認(rèn)會(huì)開(kāi)啟索引吁伺。這樣可以充分利用ORC索引減少數(shù)據(jù)掃描時(shí)間。
- 建議ETL過(guò)程中將where語(yǔ)句后經(jīng)常過(guò)濾的字段預(yù)先排序后插入數(shù)據(jù)表
- 建議在建ORC表時(shí)對(duì)于where語(yǔ)句后經(jīng)常過(guò)濾的字段添加在布隆過(guò)濾器中
CREATE TABLE bdc_dm.res_category_orc(
channel_id1 int comment '1級(jí)渠道id',
province string COMMENT '省',
city string comment '市',
uv int comment 'uv'
)
comment 'example'
partitioned by (landing_date int COMMENT '日期:yyyymmdd')
row format delimited fields terminated by '\t'
stored as orc
TBLPROPERTIES (
"orc.compress"="SNAPPY",
'orc.create.index'='true',
"orc.bloom.filter.columns"="channel_id1,uv",
'orc.bloom.filter.fpp'='0.05',
'orc.stripe.size'='10485760',
'orc.row.index.stride'='10000'
);
上面用到的參數(shù)見(jiàn)下表租谈,有些含有默認(rèn)值篮奄,可以不用設(shè)置。由于ZLIB壓縮性能不如Snappy割去,ORC文件壓縮器一般設(shè)置為snappy窟却。
參數(shù)名 | 默認(rèn)值 | 含義 |
---|---|---|
orc.compress | ZLIB | 高級(jí)壓縮器 = {NONE, ZLIB, SNAPPY} |
orc.compress.size | 262,144 | 壓縮塊大小 |
orc.stripe.size | 67,108,864 | 每個(gè)stripe塊中的字節(jié)數(shù) |
orc.row.index.stride | 10,000 | 行組大小 |
orc.create.index | true | 是否創(chuàng)建索引 |
orc.bloom.filter.columns | "" | 逗號(hào)分隔的列名列表,用于創(chuàng)建bloom過(guò)濾器 |
orc.bloom.filter.fpp | 0.05 | 布隆過(guò)濾器的假陽(yáng)性概率 (must >0.0 and <1.0) |
參考文檔
https://orc.apache.org/docs/index.html
https://orc.apache.org/specification/ORCv1/
http://www.reibang.com/p/2104d11ee0a2
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ORC
http://lxw1234.com/archives/2016/04/632.htm