本文參考:黑澤君相關博客
本文是我總結日常工作中遇到的坑,結合黑澤君相關博客,選取、補充了部分內容。
開啟 map 輸出階段壓縮可以減少 job 中 map 和 Reduce task 間數據傳輸量。
查看配置命令如下,對應的設置只要加上相關值即可,如下
是否開啟hive中間傳輸數據壓縮功能?
hive> set hive.exec.compress.intermediate;
hive.exec.compress.intermediate=false
開啟hive中間傳輸數據壓縮功能
hive> set hive.exec.compress.intermediate=true;
是否開啟mapreduce中map輸出壓縮功能
hive> set mapreduce.map.output.compress;
mapreduce.map.output.compress=true
是否設置mapreduce中map輸出數據的壓縮方式
hive> set mapreduce.map.output.compress;
mapreduce.map.output.compress=true
當 Hive 將輸出寫入到表中時,輸出內容同樣可以進行壓縮。屬性 hive.exec.compress.output 控制着這個功能。
用戶可能需要保持默認設置文件中的默認值 false,這樣默認的輸出就是非壓縮的純文本文件了。用戶可以通過在查詢語句或執行腳本中設置這個值為 true,來開啟輸出結果壓縮功能。
查看配置命令如下,對應的設置只要加上相關值即可,如下
是否開啟hive最終輸出數據壓縮功能
hive> set hive.exec.compress.output;
hive.exec.compress.output=false
是否開啟mapreduce最終輸出數據壓縮
hive> set hive.exec.compress.output;
hive.exec.compress.output=false
是否設置mapreduce最終數據輸出壓縮方式
hive> set mapreduce.output.fileoutputformat.compress.codec;
mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.DefaultCodec
設置為SnappyCodec 壓縮
hive> set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec ;
是否設置mapreduce最終數據輸出壓縮為塊壓縮(默認是行壓縮RECORD)
hive> set mapreduce.output.fileoutputformat.compress.type;
mapreduce.output.fileoutputformat.compress.type=BLOCK
文件存儲格式
Hive支持的存儲數的格式主要有:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET。
TextFile格式
默認格式,數據不做壓縮,磁盤開銷大,數據解析開銷大。
可結合Gzip、Bzip2使用。
但使用Gzip這種方式,hive不會對數據進行切分,從而無法對數據進行並行操作。
Orc格式
Orc (Optimized Row Columnar)是Hive 0.11版里引入的新的存儲格式。
Index Data
Index Data 包括每一列的最小值和最大值,以及每一列中的行位置。(也可以包含bit field or bloom filter ) 行索引項提供了偏移量,使您能夠在解壓縮塊中查找正確的壓縮塊和字節。
注意,ORC索引僅用於選擇stripes 和 row groups,而不用於回答查詢。
擁有相對頻繁的行索引項可以在stripe 內跳過行,以便快速讀取,盡管stripe 很大。默認情況下,可以跳過每10,000行。
Row Data
存的是具體的數據,先取部分行,然后對這些行按列進行存儲。對每個列進行了編碼,分成多個Stream來存儲。
Stripe Footer
存的是各個Stream的類型,長度等信息。
File Footer
每個文件有一個File Footer,這里面存的是每個Stripe的行數,每個Column的數據類型信息等;
PostScript
每個文件的尾部是一個PostScript,這里面記錄了整個文件的壓縮類型以及FileFooter的長度信息等。
在讀取文件時,會seek到文件尾部讀PostScript,從里面解析到File Footer長度,再讀FileFooter,從里面解析到各個Stripe信息,再讀各個Stripe,即從后往前讀。
示例:
數據量:19017003
hive> CREATE TABLE tmp.orcTest stored AS ORC
> TBLPROPERTIES
> ('orc.compress'='SNAPPY',
> 'orc.create.index'='true',
> 'orc.bloom.filter.fpp'='0.05',
> 'orc.stripe.size'='10485760',
> 'orc.row.index.stride'='10000')
> AS
> SELECT
> *
> FROM tmp.textFileTest
Stage-Stage-1: Map: 16 Reduce: 62 Cumulative CPU: 1350.32 sec HDFS Read: 4140450145 HDFS Write: 250057437 SUCCESS
向表中加載數據(不能使用load方式加載數據,需要insert into方式或者上述方式,即一定要通過MapReduce任務加載數據)
orc:不使用索引
hive> set hive.optimize.index.filter=false;
hive> select * from tmp.orcTest where userid ='02012138';
Query ID = hdfs_20190716114646_cb74ab6e-3d7f-42a8-b1e8-703abd89c420
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 5 Cumulative CPU: 32.88 sec HDFS Read: 250016639 HDFS Write: 175 SUCCESS
Total MapReduce CPU Time Spent: 32 seconds 880 msec
OK
02012138 2019-06-16 00:21:03.000000000 10000 0 20190616
Time taken: 13.935 seconds, Fetched: 1 row(s)
很明顯,掃描了所有記錄。再使用索引查詢:
orc:使用索引
hive> set hive.optimize.index.filter=true;
hive> select * from tmp.orcTest where userid ='02012138';
Query ID = hdfs_20190716114747_dd02a4a3-7a25-424b-84d8-a314e918464f
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 5 Cumulative CPU: 24.77 sec HDFS Read: 58144301 HDFS Write: 175 SUCCESS
Total MapReduce CPU Time Spent: 24 seconds 770 msec
OK
02012138 2019-06-16 00:21:03.000000000 10000
Time taken: 12.916 seconds, Fetched: 1 row(s)
可以看到,只掃描了部分記錄,即根據Row Group Index中的min/max跳過了WHERE條件中不包含的stripes,索引有效果。
TeXtFile
hive> select * from tmp.tb_tmp_tms_stb_errorcode where userid ='02012138';
Query ID = hdfs_20190716114747_ac4b272c-4317-4b47-9726-91f297fc1af8
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 16 Cumulative CPU: 112.89 sec HDFS Read: 4140148821 HDFS Write: 175 SUCCESS
Total MapReduce CPU Time Spent: 1 minutes 52 seconds 890 msec
OK
02012138 2019-06-16 00:21:03.000000000 10000
Time taken: 17.072 seconds, Fetched: 1 row(s)
數據未經過壓縮,讀取全集數據
注:我看一些文檔說,Orc列存儲,如果用 =,> 之類 篩選列不會觸發 mapReduce,經過測試,還是觸發了,而且查詢時間整體上比TextFile 短。
關於mapReduce的后續再找找答案,或者有知道的道友分享下。
Parquet格式
這個東東我用的少,了解不多,在這里就僅僅標記一下
Parquet文件是以二進制方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數據和元數據,因此Parquet格式文件是自解析的。
通常情況下,在存儲Parquet數據的時候會按照Block大小設置行組的大小,由於一般情況下每一個Mapper任務處理數據的最小單位是一個Block,這樣可以把每一個行組由一個Mapper任務處理,增大任務執行並行度。Parquet文件的格式如下圖所示。
各種存儲文件的查詢速度總結:經過驗證,查詢速度相近, orc、parquet有時候會比TextFile稍微快一丟丟。
小結:在實際的項目開發當中,hive表的數據存儲格式一般選擇:orc或parquet。壓縮方式一般選擇snappy或lzo。(使用壓縮后可大量節省空間)
存儲和壓縮結合
- 查看hadoop支持的壓縮方式
[hdfs@tmpe2e02 tmp_lillcol]$ hadoop checknative
19/07/16 14:21:20 INFO bzip2.Bzip2Factory: Successfully loaded & initialized native-bzip2 library system-native
19/07/16 14:21:20 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop: true /opt/cloudera/parcels/CDH-5.7.2-1.cdh5.7.2.p0.18/lib/hadoop/lib/native/libhadoop.so.1.0.0
zlib: true /lib64/libz.so.1
snappy: true /opt/cloudera/parcels/CDH-5.7.2-1.cdh5.7.2.p0.18/lib/hadoop/lib/native/libsnappy.so.1
lz4: true revision:10301
bzip2: true /lib64/libbz2.so.1
openssl: true /usr/local/ssl/lib/libcrypto.so
- HiveQL語句指定ORC文件格式配置
配置 | 默認值 | 備注 |
---|---|---|
orc.compress | ZLIB | 高級壓縮(one of NONE, ZLIB, SNAPPY) |
orc.compress.size | 262,144 | 每個壓縮塊中的字節數 |
orc.stripe.size | 67,108,864 | 每條stripe中的字節數 |
orc.row.index.stride | 10,000 | 索引條目之間的行數(必須是>= 1000) |
orc.create.index | true | 是否創建行索引 |
orc.bloom.filter.columns | "" | 逗號分隔的列名列表,應該為其創建bloom過濾器 |
orc.bloom.filter.fpp | 0.05 | bloom過濾器的誤報概率(必須是>0.0和<1.0) |
案例:
CREATE TABLE tmp.orcTest stored AS ORC
TBLPROPERTIES
('orc.compress'='SNAPPY',
'orc.create.index'='true',
'orc.bloom.filter.fpp'='0.05',
'orc.stripe.size'='10485760',
'orc.row.index.stride'='10000')
AS
SELECT
*
FROM tmp.orcTextFile
DISTRIBUTE BY userid sort BY userid;
orc存儲文件默認采用ZLIB壓縮。ZLIB壓縮率比snappy的高,但是ZLIB解壓縮速率很低。
Fetch抓取
Fetch抓取是指,Hive中對某些情況的查詢可以不必使用MapReduce計算。
例如:SELECT * FROM orcTest
; 在這種情況下,Hive可以簡單地讀取orcTest對應的存儲目錄下的文件,然后輸出查詢結果到控制台。
配置
hive-default.xml.template 中 hive.fetch.task.conversion
<property>
<name>hive.fetch.task.conversion</name>
<value>more</value>
<description>
可選值 [none, minimal, more].
一些select查詢可以轉換為單個獲取任務,從而最小化延遲。
目前,查詢應該是單一來源的,沒有任何子查詢,也不應該有任何聚合或區別(引起RS)、橫向視圖和連接。
0. none : 禁用 hive.fetch.task.conversion
1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only
2. more : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)
</description>
</property>
測試:
hive> set hive.fetch.task.conversion; //查詢當前配置
hive.fetch.task.conversion=minimal
hive> set hive.fetch.task.conversion=none;
hive> select userid from tmp.orcTest limit 1;
Query ID = hdfs_20190716151010_29239e97-a06c-47aa-9958-f1964ab8eb17
Total jobs = 1
Launching Job 1 out of 1
.
.
.
Stage-Stage-1: Map: 5 Cumulative CPU: 15.09 sec HDFS Read: 4155591 HDFS Write: 661 SUCCESS
Total MapReduce CPU Time Spent: 15 seconds 90 msec
OK
02012138
Time taken: 13.908 seconds, Fetched: 10 row(s)
hive> set hive.fetch.task.conversion=more;
hive> select userid from tmp.orcTest limit 10;
OK
02012138
Time taken: 0.025 seconds, Fetched: 10 row(s)
把hive.fetch.task.conversion設置成none,然后執行查詢語句,都會執行MapReduce程序。
本地模式
有時Hive的輸入數據量是非常小的。
在這種情況下,為查詢觸發執行任務消耗的時間可能會比實際job的執行時間要多的多。
對於大多數這種情況,Hive可以通過本地模式在單台機器上處理所有的任務。
對於小數據集,執行時間可以明顯被縮短。
// 開啟本地mr模式
hive> set hive.exec.mode.local.auto;
hive.exec.mode.local.auto=false
// 設置local mr的最大輸入數據量,當輸入數據量小於這個值時采用local mr的方式,默認為134217728,即128M
hive> set hive.exec.mode.local.auto.inputbytes.max;
hive.exec.mode.local.auto.inputbytes.max=134217728
// 設置local mr的最大輸入文件個數,當輸入文件個數小於這個值時采用local mr的方式,默認為4
hive> set hive.exec.mode.local.auto.input.files.max;
hive.exec.mode.local.auto.input.files.max=4
上面是查看參數值的方法,對應的設置直接改成設置值即可。
創建測表
hive> CREATE TABLE tmp.orclocal stored AS ORC
> TBLPROPERTIES
> ('orc.compress'='SNAPPY',
> 'orc.create.index'='true',
> 'orc.bloom.filter.fpp'='0.05',
> 'orc.stripe.size'='10485760',
> 'orc.row.index.stride'='10000')
> AS
> SELECT
> *
> FROM tmp.orcTest
> DISTRIBUTE BY userid sort BY userid limit 1000;
查看文件數量:1個 符合配置
hive> !hadoop fs -du -h hdfs://ns1/user/hive/warehouse/tmp.db/orclocal;
22.5 K 45.1 K hdfs://ns1/user/hive/warehouse/tmp.db/orclocal/000000_0
關閉本地模式,並執行查詢語句
hive> set hive.exec.mode.local.auto=false;
hive> select count(*) from tmp.orclocal;
OK
1000
Time taken: 18.98 seconds, Fetched: 1 row(s)
開啟本地模式,並執行查詢語句
hive> set hive.exec.mode.local.auto=true;
hive> select count(*) from tmp.orclocal;
OK
1000
Time taken: 1.576 seconds, Fetched: 1 row(s)
時間對比有點不真實了....,但是測試幾次,在小文件的情況下開啟本地模式確實優勢很大