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