一文讀懂Hive底層數(shù)據(jù)存儲(chǔ)格式
本文講解 Hive 的數(shù)據(jù)存儲(chǔ),是 Hive 操作數(shù)據(jù)的基礎(chǔ)。選擇一個(gè)合適的底層數(shù)據(jù)存儲(chǔ)文件格式,即使在不改變當(dāng)前 Hive SQL 的情況下,性能也能得到數(shù)量級(jí)的提升。這種優(yōu)化方式對(duì)學(xué)過 MySQL 等關(guān)系型數(shù)據(jù)庫(kù)的小伙伴并不陌生,選擇不同的數(shù)據(jù)存儲(chǔ)引擎,代表著不同的數(shù)據(jù)組織方式,對(duì)于數(shù)據(jù)庫(kù)的表現(xiàn)會(huì)有不同的影響。
Hive 數(shù)據(jù)存儲(chǔ)常用的格式如下:
- 行式存儲(chǔ):文本格式(TextFile)二進(jìn)制序列化文件 (SequenceFile)
- 列式存儲(chǔ):行列式文件(RCFile)優(yōu)化的行列式文件(ORCFile)Apache Parquet
注:RCFile 和 ORCFile 并不是純粹的列式存儲(chǔ),它是先基于行對(duì)數(shù)據(jù)表進(jìn)行分組(行組),然后對(duì)行組進(jìn)行列式存儲(chǔ)
我們看下這幾種存儲(chǔ)結(jié)構(gòu)的優(yōu)缺點(diǎn):
行存儲(chǔ)模式就是把一整行存在一起,包含所有的列,這是最常見的模式。這種結(jié)構(gòu)能很好的適應(yīng)動(dòng)態(tài)的查詢。
比如:select a from tableA 和 select a, b, c, d, e, f, g from tableA這樣兩個(gè)查詢其實(shí)查詢的開銷差不多,都需要把所有的行讀進(jìn)來過一遍,拿出需要的列。
而且這種情況下,屬于同一行的數(shù)據(jù)都在同一個(gè) HDFS 塊上,重建一行數(shù)據(jù)的成本比較低。
但是這樣做有兩個(gè)主要的弱點(diǎn):
- 當(dāng)一行中有很多列,而我們只需要其中很少的幾列時(shí),我們也不得不把一行中所有的列讀進(jìn)來,然后從中取出一些列。這樣大大降低了查詢執(zhí)行的效率。
- 基于多個(gè)列做壓縮時(shí),由于不同的列數(shù)據(jù)類型和取值范圍不同,壓縮比不會(huì)太高。
垂直的列存儲(chǔ)結(jié)構(gòu):
列存儲(chǔ)是將每列單獨(dú)存儲(chǔ)或者將某幾個(gè)列作為列組存在一起。列存儲(chǔ)在執(zhí)行查詢時(shí)可以避免讀取不必要的列。而且一般同列的數(shù)據(jù)類型一致,取值范圍相對(duì)多列混合更小,在這種情況下壓縮數(shù)據(jù)能達(dá)到比較高的壓縮比。
但是這種結(jié)構(gòu)在重建行時(shí)比較費(fèi)勁,尤其當(dāng)一行的多個(gè)列不在一個(gè) HDFS 塊上的時(shí)候。比如我們從第一個(gè) DataNode 上拿到 column A,從第二個(gè) DataNode 上拿到了 column B,又從第三個(gè) DataNode 上拿到了 column C,當(dāng)要把 A,B,C 拼成一行時(shí),就需要把這三個(gè)列放到一起重建出行,需要比較大的網(wǎng)絡(luò)開銷和運(yùn)算開銷。
混合的 PAX 存儲(chǔ)結(jié)構(gòu):
PAX 結(jié)構(gòu)是將行存儲(chǔ)和列存儲(chǔ)混合使用的一種結(jié)構(gòu),主要是傳統(tǒng)數(shù)據(jù)庫(kù)中提高 CPU 緩存利用率的一種方法,并不能直接用到 HDFS 中。但是 RCFile 和 ORC 是繼承自它的思想,先按行存再按列存。
接下來我們看下在 Hive 中常用的幾種存儲(chǔ)格式:
本文重點(diǎn)講解最后兩種:Apache ORC 和 Apache Parquet,因?yàn)樗鼈円云涓咝У臄?shù)據(jù)存儲(chǔ)和數(shù)據(jù)處理性能得以在實(shí)際的生產(chǎn)環(huán)境中大量運(yùn)用。
一、TextFile
TextFile 為 Hive 默認(rèn)格式,建表時(shí)不指定則默認(rèn)為這個(gè)格式,導(dǎo)入數(shù)據(jù)時(shí)會(huì)直接把數(shù)據(jù)文件拷貝到 hdfs 上不進(jìn)行處理。
創(chuàng)建一個(gè) TextFile 格式的 Hive 表:
create table if not exists textfile_table
(
ueserid STRING,
movieid STRING,
rating STRING,
ts STRING
)
row formated delimated fields terminated by '\t'
stored as textfile; -- 可不指定(默認(rèn)格式)
向 TextFile 表中加載數(shù)據(jù):
load data local inpath "/root/rating.csv" overwrite into table textfile_table
TextFile 優(yōu)缺點(diǎn):
TextFile 格式因?yàn)椴粚?duì)導(dǎo)入的數(shù)據(jù)文件做處理,所以可以直接使用 load 方式加載數(shù)據(jù),其他存儲(chǔ)格式則不能使用 load 直接導(dǎo)入數(shù)據(jù)文件。所以 TextFile 的加載速度是最高的。
TextFile 格式雖然可以使用 Gzip 壓縮算法,但壓縮后的文件不支持 split。在反序列化過程中,必須逐個(gè)字符判斷是不是分隔符和行結(jié)束符,因此反序列化開銷會(huì)比 SequenceFile 高幾十倍。
二、SequenceFile
SequenceFile 是 Hadoop API 提供的一種二進(jìn)制文件支持,其具有使用方便、可分割、可壓縮的特點(diǎn)。
SequenceFIle 的內(nèi)部格式取決于是否啟用壓縮,如果是壓縮,則又可以分為記錄壓縮和塊壓縮。
無壓縮(NONE):如果沒有啟用壓縮(默認(rèn)設(shè)置)那么每個(gè)記錄就由它的記錄長(zhǎng)度(字節(jié)數(shù))、鍵的長(zhǎng)度,鍵和值組成。長(zhǎng)度字段為 4 字節(jié)。
記錄壓縮(RECORD):記錄壓縮格式與無壓縮格式基本相同,不同的是值字節(jié)是用定義在頭部的編碼器來壓縮。注意:鍵是不壓縮的。
塊壓縮(BLOCK):塊壓縮一次壓縮多個(gè)記錄,因此它比記錄壓縮更緊湊,而且一般優(yōu)先選擇。當(dāng)記錄的字節(jié)數(shù)達(dá)到最小大小,才會(huì)添加到塊。該最小值由 io.seqfile.compress.blocksize 中的屬性定義。默認(rèn)值是 1000000 字節(jié)。格式為記錄數(shù)、鍵長(zhǎng)度、鍵、值長(zhǎng)度、值。Record 壓縮率低,一般建議使用 BLOCK 壓縮。
創(chuàng)建一個(gè) SequenceFile 格式的 Hive 表:
create table if not exists seqfile_table
(
ueserid STRING,
movieid STRING,
rating STRING,
ts STRING
)
row format delimited
fields terminated by '\t'
stored as sequencefile;
設(shè)置壓縮格式為塊壓縮:
set mapred.output.compression.type=BLOCK;
向 SequenceFile 表中加載數(shù)據(jù):
insert overwrite table seqfile_table select * from textfile_table;
SequenceFile 優(yōu)點(diǎn):
- 支持基于記錄(Record)或塊(Block)的數(shù)據(jù)壓縮。
- 支持 splitable,能夠作為 MapReduce 的輸入分片。
- 修改簡(jiǎn)單:主要負(fù)責(zé)修改相應(yīng)的業(yè)務(wù)邏輯,而不用考慮具體的存儲(chǔ)格式。
SequenceFile 的缺點(diǎn):
- 需要一個(gè)合并文件的過程,且合并后的文件不方便查看。
三、RCFile
RCFile 文件格式是 FaceBook 開源的一種 Hive 的文件存儲(chǔ)格式,首先將表分為幾個(gè)行組,對(duì)每個(gè)行組內(nèi)的數(shù)據(jù)進(jìn)行按列存儲(chǔ),每一列的數(shù)據(jù)都是分開存儲(chǔ),正是先水平劃分,再垂直劃分的理念。
圖片
首先對(duì)表進(jìn)行行劃分,分成多個(gè)行組。一個(gè)行組主要包括:
- 16 字節(jié)的 HDFS 同步塊信息,主要是為了區(qū)分一個(gè) HDFS 塊上的相鄰行組;
- 元數(shù)據(jù)的頭部信息主要包括該行組內(nèi)的存儲(chǔ)的行數(shù)、列的字段信息等等;
- 數(shù)據(jù)部分我們可以看出 RCFile 將每一行,存儲(chǔ)為一列,將一列存儲(chǔ)為一行,因?yàn)楫?dāng)表很大,我們的字段很多的時(shí)候,我們往往只需要取出固定的一列就可以。
在一般的行存儲(chǔ)中 select a from table,雖然只是取出一個(gè)字段的值,但是還是會(huì)遍歷整個(gè)表,所以效果和 select * from table 一樣,在 RCFile 中,像前面說的情況,只會(huì)讀取該行組的一行。
創(chuàng)建一個(gè) RCFile 的表:
create table if not exists rcfile_table
(
ueserid STRING,
movieid STRING,
rating STRING,
ts STRING
)
row format delimited fields terminated by '\t'
stored as rcfile;
在存儲(chǔ)空間上:
RCFile 是行劃分,列存儲(chǔ),采用游程編碼,相同的數(shù)據(jù)不會(huì)重復(fù)存儲(chǔ),很大程度上節(jié)約了存儲(chǔ)空間,尤其是字段中包含大量重復(fù)數(shù)據(jù)的時(shí)候。
懶加載:
數(shù)據(jù)存儲(chǔ)到表中都是壓縮的數(shù)據(jù),Hive 讀取數(shù)據(jù)的時(shí)候會(huì)對(duì)其進(jìn)行解壓縮,但是會(huì)針對(duì)特定的查詢跳過不需要的列,這樣也就省去了無用的列解壓縮。
如:
select c from table where a>1;
針對(duì)行組來說,會(huì)對(duì)一個(gè)行組的 a 列進(jìn)行解壓縮,如果當(dāng)前列中有 a>1 的值,然后才去解壓縮 c。若當(dāng)前行組中不存在 a>1 的列,那就不用解壓縮 c,從而跳過整個(gè)行組。
四、ORCFile
1. ORC相比較 RCFile 的優(yōu)點(diǎn)
ORC 是在一定程度上擴(kuò)展了 RCFile,是對(duì) RCFile 的優(yōu)化:
- ORC 擴(kuò)展了 RCFile 的壓縮,除了 Run-length(游程編碼),引入了字典編碼和 Bit 編碼。
- 每個(gè) task 只輸出單個(gè)文件,這樣可以減少 NameNode 的負(fù)載;
- 支持各種復(fù)雜的數(shù)據(jù)類型,比如:datetime,decimal,以及一些復(fù)雜類型(struct, list, map,等);
- 文件是可切分(Split)的。在 Hive 中使用 ORC 作為表的文件存儲(chǔ)格式,不僅節(jié)省 HDFS 存儲(chǔ)資源,查詢?nèi)蝿?wù)的輸入數(shù)據(jù)量減少,使用的 MapTask 也就減少了。
采用字典編碼,最后存儲(chǔ)的數(shù)據(jù)便是字典中的值,及每個(gè)字典值的長(zhǎng)度以及字段在字典中的位置;采用 Bit 編碼,對(duì)所有字段都可采用 Bit 編碼來判斷該列是否為 null, 如果為 null 則 Bit 值存為 0,否則存為 1,對(duì)于為 null 的字段在實(shí)際編碼的時(shí)候不需要存儲(chǔ),也就是說字段若為 null,是不占用存儲(chǔ)空間的。
2. ORC的基本結(jié)構(gòu)
ORCFile 在 RCFile 基礎(chǔ)上引申出來 Stripe 和 Footer 等。每個(gè) ORC 文件首先會(huì)被橫向切分成多個(gè) Stripe,而每個(gè) Stripe 內(nèi)部以列存儲(chǔ),所有的列存儲(chǔ)在一個(gè)文件中,而且每個(gè) stripe 默認(rèn)的大小是 250MB,相對(duì)于 RCFile 默認(rèn)的行組大小是 4MB,所以比 RCFile 更高效。
下圖是 ORC 的文件結(jié)構(gòu)示意圖:
圖片
ORC 文件結(jié)構(gòu)由三部分組成:
- 條帶(stripe):ORC 文件存儲(chǔ)數(shù)據(jù)的地方。
- 文件腳注(file footer):包含了文件中 stripe 的列表,每個(gè) stripe 的行數(shù),以及每個(gè)列的數(shù)據(jù)類型。它還包含每個(gè)列的最小值、最大值、行計(jì)數(shù)、 求和等聚合信息。
- postscript:含有壓縮參數(shù)和壓縮大小相關(guān)的信息。
stripe 結(jié)構(gòu)同樣可以分為三部分:index data、rows data 和 stripe footer:
- index data:保存了所在條帶的一些統(tǒng)計(jì)信息,以及數(shù)據(jù)在 stripe 中的位置索引信息。
- rows data:數(shù)據(jù)存儲(chǔ)的地方,由多個(gè)行組構(gòu)成,數(shù)據(jù)以流(stream)的形式進(jìn)行存儲(chǔ)。
- stripe footer:保存數(shù)據(jù)所在的文件目錄。
rows data 存儲(chǔ)兩部分的數(shù)據(jù),即 metadata stream 和 data stream:
- metadata stream:用于描述每個(gè)行組的元數(shù)據(jù)信息。
- data stream:存儲(chǔ)數(shù)據(jù)的地方。
ORC 在每個(gè)文件中提供了 3 個(gè)級(jí)別的索引:
- 文件級(jí):這一級(jí)的索引信息記錄文件中所有 stripe 的位置信息,以及文件中所存儲(chǔ)的每列數(shù)據(jù)的統(tǒng)計(jì)信息。
- 條帶級(jí)別:該級(jí)別索引記錄每個(gè) stripe 所存儲(chǔ)數(shù)據(jù)的統(tǒng)計(jì)信息。
- 行組級(jí)別:在 stripe 中,每 10000 行構(gòu)成一個(gè)行組,該級(jí)別的索引信息 就是記錄這個(gè)行組中存儲(chǔ)的數(shù)據(jù)的統(tǒng)計(jì)信息。
程序可以借助 ORC 提供的索引加快數(shù)據(jù)查找和讀取效率。程序在查詢 ORC 文件類型的表時(shí),會(huì)先讀取每一列的索引信息,將查找數(shù)據(jù)的條件和索引信息進(jìn)行對(duì)比,找到滿足查找條件的文件。
接著根據(jù)文件中的索引信息,找到存儲(chǔ)對(duì)應(yīng)的查詢條件數(shù)據(jù) stripe,再借助 stripe 的索引信息讀文件中滿足查詢條件的所有 stripe 塊。
之后再根據(jù) stripe 中每個(gè)行組的索引信息和查詢條件比對(duì)的結(jié)果,找到滿足要求的行組。
通過 ORC 這些索引,可以快速定位滿足查詢的數(shù)據(jù)塊,規(guī)避大部分不滿足查詢條件的文件和數(shù)據(jù)塊,相比于讀取傳統(tǒng)的數(shù)據(jù)文件,進(jìn)行查找時(shí)需要遍歷全部的數(shù)據(jù),使用 ORC 可以避免磁盤和網(wǎng)絡(luò) I/O 的浪費(fèi),提升程序的查找效率,提升整個(gè)集群的工作負(fù)載。
3. ORC 的數(shù)據(jù)類型
Hive 在使用 ORC 文件進(jìn)行存儲(chǔ)數(shù)據(jù)時(shí),描述這些數(shù)據(jù)的字段信息、字段 類型信息及編碼等相關(guān)信息都是和 ORC 中存儲(chǔ)的數(shù)據(jù)放在一起的。
ORC 中每個(gè)塊中的數(shù)據(jù)都是自描述的,不依賴外部的數(shù)據(jù),也不存儲(chǔ)在 Hive 的元數(shù)據(jù)庫(kù)中。
ORC 提供的數(shù)據(jù)數(shù)據(jù)類型包含如下內(nèi)容:
- 整型:包含 boolean(1bit)、tinyint(8bit)、smallint(16bit)、int(32bit)、bigint(64bit)。
- 浮點(diǎn)型:包含 float 和 double。
- 字符串類型:包含 string、char 和 varchar。
- 二進(jìn)制類型:包含 binary。
- 日期和時(shí)間類型:包含 timestamp 和 date。·
- 復(fù)雜類型:包含 struct、list、map 和 union 類型。
目前 ORC 基本已經(jīng)兼容了日常所能用到的絕大部分的字段類型。另外,ORC 中所有的類型都可以接受 NULL 值。
4. ORC 的 ACID 事務(wù)的支持
在 Hive 0.14 版本以前,Hive 表的數(shù)據(jù)只能新增或者整塊刪除分區(qū)或表,而不能對(duì)表的單個(gè)記錄進(jìn)行修改。
在 Hive 0.14 版本后,ORC 文件能夠確保 Hive 在工作時(shí)的原子性、一致性、隔離性和持久性的 ACID 事務(wù)能夠被正確地得到使用,使得對(duì)數(shù)據(jù)更新操作成為可能。
Hive 是面向 OLAP 的,所以它的事務(wù)也和 RDMBS 的事務(wù)有一定的區(qū)別。Hive 的事務(wù)被設(shè)計(jì)成每個(gè)事務(wù)適用于更新大批量的數(shù)據(jù),而不建議用事務(wù)頻繁地更新小批量的數(shù)據(jù)。
創(chuàng)建 Hive 事務(wù)表的方法:
- 設(shè)置 hive 環(huán)境參數(shù):
--開啟并發(fā)支持,支持插入、刪除和更新的事務(wù)
set hive.support.cnotallow=true;
--支持ACID事務(wù)的表必須為分桶表
set hive.enforce.bucketing=true;
--開啟事物需要開啟動(dòng)態(tài)分區(qū)非嚴(yán)格模式
set hive.exec.dynamic.partition.mode=nonstrict;
--設(shè)置事務(wù)所管理類型為org.apache.hive.ql.lockmgr.DbTxnManager
--原有的org.apache.hadoop.hive.ql.lockmgr.DummyTxnManager不支持事務(wù)
set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
--開啟在相同的一個(gè)meatore實(shí)例運(yùn)行初始化和清理的線程
set hive.compactor.initiator.notallow=true;
--設(shè)置每個(gè)metastore實(shí)例運(yùn)行的線程數(shù)
set hive.compactor.worker.threads=1;
- 創(chuàng)建表:
create table student_txn
(id int,
name string
)
clustered by (id) into 2 buckets --必須支持分桶
stored as orc TBLPROPERTIES ('transactional'='true'); --在表屬性中添加支持事務(wù)
- 插入數(shù)據(jù):
--插入id為1001,名字為'student_1001
insert into table student_txn values('1001','student_1001');
- 更新數(shù)據(jù):
update student_txn
set name='student_lzh'
where id='1001';
- 查看表的數(shù)據(jù),最終會(huì)發(fā)現(xiàn) id 為 1001 被改為 sutdent_lzh;
5. ORC 相關(guān)的 Hive 配置
表的屬性配置項(xiàng)有如下幾個(gè):
- orc.compress:表示 ORC 文件的壓縮類型,可選的類型有 NONE、ZLIB 和 SNAPPY,默認(rèn)值是 ZLIB。
- orc.compress.size:表示壓縮塊(chunk)的大小,默認(rèn)值是 262144(256KB)。
- orc.stripe.size:寫 stripe,可以使用的內(nèi)存緩沖池大小,默認(rèn)值是 67108864(64MB)。
- orc.row.index.stride:行組級(jí)別索引的數(shù)據(jù)量大小,默認(rèn)是 10000,必須要設(shè)置成大于等于 10000 的數(shù)。
- orc.create.index:是否創(chuàng)建行組級(jí)別索引,默認(rèn)是 true。
- orc.bloom.filter.columns:需要?jiǎng)?chuàng)建布隆過濾的組。
- orc.bloom.filter.fpp:使用布隆過濾器的假正(False Positive)概率,默認(rèn)值是 0.05。
注:在 Hive 中使用布隆(bloom)過濾器,可以用較少的文件空間快速判定數(shù)據(jù)是否存在于表中,但是也存在將不屬于這個(gè)表的數(shù)據(jù)判定為屬于這個(gè)這表的情況,這個(gè)情況稱之為假正概率,可以手動(dòng)調(diào)整該概率,但概率越低,布隆過濾器所需要的空間越多。
五、Parquet
Parquet 是另外的一種高性能行列式的存儲(chǔ)結(jié)構(gòu),可以適用多種計(jì)算框架,被多種查詢引擎所支持,包括 Hive、Impala、Drill 等。
1. Parquet 基本結(jié)構(gòu):
在一個(gè) Parquet 類型的 Hive 表文件中,數(shù)據(jù)被分成多個(gè)行組,每個(gè)列塊又被拆分成若干的頁(yè)(Page),如下圖所示:
Parquet的文件結(jié)構(gòu)
Parquet 在存儲(chǔ)數(shù)據(jù)時(shí),也同 ORC 一樣記錄這些數(shù)據(jù)的元數(shù)據(jù),這些元數(shù)據(jù)也同 Parquet 的文件結(jié)構(gòu)一樣,被分成多層文件級(jí)別的元數(shù)據(jù)、列塊級(jí)別的元數(shù)據(jù)及頁(yè)級(jí)別的元數(shù)據(jù)。
文件級(jí)別的元數(shù)據(jù)(fileMetadata)記錄主要如下:
- 表結(jié)構(gòu)信息(Schema);
- 該文件的記錄數(shù);
- 該文件擁有的行組,以及每個(gè)行組的數(shù)據(jù)總量,記錄數(shù);
- 每個(gè)行組下,列塊的文件偏移量。
列塊的元數(shù)據(jù)信息如下:
- 記錄該列塊的未壓縮和壓縮后的數(shù)據(jù)大小和壓縮編碼;
- 數(shù)據(jù)頁(yè)的偏移量;
- 索引頁(yè)的偏移量;
- 列塊的數(shù)據(jù)記錄數(shù)。
頁(yè)頭的元數(shù)據(jù)信息如下:
- 該頁(yè)的編碼信息;
- 該頁(yè)的數(shù)據(jù)記錄數(shù)。
程序可以借助 Parquet 的這些元數(shù)據(jù),在讀取數(shù)據(jù)時(shí)過濾掉不需要讀取的大部分文件數(shù)據(jù),加快程序的運(yùn)行速度。
同 ORC 的元數(shù)據(jù)一樣,Parquet 的這些元數(shù)據(jù)信息能夠幫助提升程序的運(yùn)行速度,但是 ORC 在讀取數(shù)據(jù)時(shí)又做了一定的優(yōu)化,增強(qiáng)了數(shù)據(jù)的讀取效率。在查詢時(shí)所消耗的集群資源比 Parquet 類型少。
Parquet 在嵌套式結(jié)構(gòu)支持比較完美,而 ORC 多層級(jí)嵌套表達(dá)起來比較復(fù)雜,性能損失較大。
2. Parquet 的相關(guān)配置:
可以根據(jù)不同場(chǎng)景需求進(jìn)行適當(dāng)?shù)膮?shù)調(diào)整,實(shí)現(xiàn)程序優(yōu)化。
- parquet.block.size:默認(rèn)值為 134217728byte,即 128MB,表示 RowGroup 在內(nèi)存中的塊大小。該值設(shè)置得大,可以提升 Parquet 文件的讀取效率,但是相應(yīng)在寫的時(shí)候需要耗費(fèi)更多的內(nèi)存。
- parquet.page.size:默認(rèn)值為 1048576byte,即 1MB,表示每個(gè)頁(yè) (page)的大小。這個(gè)特指壓縮后的頁(yè)大小,在讀取時(shí)會(huì)先將頁(yè)的數(shù)據(jù)進(jìn)行解壓。頁(yè)是 Parquet 操作數(shù)據(jù)的最小單位,每次讀取時(shí)必須讀完一整頁(yè)的數(shù)據(jù)才能訪問數(shù)據(jù)。這個(gè)值如果設(shè)置得過小,會(huì)導(dǎo)致壓縮時(shí)出現(xiàn)性能問題。
- parquet.compression:默認(rèn)值為 UNCOMPRESSED(不壓縮),表示頁(yè)的壓縮式??梢允褂玫膲嚎s方式有 UNCOMPRESSED、SNAPPY、GZIP 和 LZO。
- parquet.enable.dictionary:默認(rèn)為 true,表示是否啟用字典編碼。
- parquet.dictionary.page.size:默認(rèn)值為 1048576byte,即 1MB。在使用字典編碼時(shí),會(huì)在 Parquet 的每行每列中創(chuàng)建一個(gè)字典頁(yè)。使用字典編碼,如果存儲(chǔ)的數(shù)據(jù)頁(yè)中重復(fù)的數(shù)據(jù)較多,能夠起到一個(gè)很好的壓縮效果,也能減少每個(gè)頁(yè)在內(nèi)存的占用。
3. 使用Spark引擎時(shí) Parquet 表的壓縮格式配置:
Spark 天然支持 Parquet,并為其推薦的存儲(chǔ)格式(默認(rèn)存儲(chǔ)為parquet)。
對(duì)于 Parquet 表的壓縮格式分以下兩種情況進(jìn)行配置:
對(duì)于分區(qū)表:
需要通過 Parquet 本身的配置項(xiàng) parquet.compression 設(shè)置 Parquet 表的數(shù)據(jù)壓縮格式。如在建表語句中設(shè)置:"parquet.compression"="snappy"。
對(duì)于非分區(qū)表:
需要通過 spark.sql.parquet.compression.code 配置項(xiàng)來設(shè)置 Parquet 類型的數(shù)據(jù)壓縮格式。直接設(shè)置parquet.compression 配置項(xiàng)是無效的,因?yàn)樗鼤?huì)讀取 spark.sql.parquet.compression.codec 配置項(xiàng)的值。
當(dāng) spark.sql.parquet.compression.codec 未做設(shè)置時(shí)默認(rèn)值為 snappy,parquet.compression 會(huì)讀取該默認(rèn)值。
因此,spark.sql.parquet.compression.codec 配置項(xiàng)只適用于設(shè)置非分區(qū)表的 Parquet 壓縮格式。
4. Parquet 和 ORC 壓縮格式對(duì)比:
表類型 | 默認(rèn)壓縮 | 支持的壓縮格式 | 描述 |
ORC | Zlib | None、Zlib、Snappy | ORC 可以選擇Zlib或Snappy壓縮,Snappy需要額外安裝 |
Parquet | Uncompressed | Uncompressed、Snappy、Gzip、Lzo | Parquet使用Gzip壓縮率最高,使用 Lzo、Snappy效率高 |
ORC 表支持 None、Zlib、Snappy 壓縮,默認(rèn)為 ZLIB 壓縮。但這 3 種壓縮格式不支持切分,所以適合單個(gè)文件不是特別大的場(chǎng)景。使用 Zlib 壓縮率高,但效率差一些;使用 Snappy 效率高,但壓縮率低。
Parquet 表支持 Uncompress、Snappy、Gzip、Lzo 壓縮,默認(rèn)不壓縮(Uncompressed)。其中 Lzo 壓縮是支持切分的,所以在表的單個(gè)文件較大的場(chǎng)景會(huì)選擇 Lzo 格式。Gzip 方式壓縮率高,效率低;而 Snappy、Lzo 效率高,壓縮率低。