1、創建一個普通的表
create table test_user1(id int, name string,code string,code_id string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
2、查看錶信息
DESCRIBE FORMATTED test_user1;
我們從該表的描述信息介紹建表時的一些可優化點。
2.1表的文件數
numFiles表示表中含有的文件數,當文件數過多時可能意味著該表的小文件過多,這時候我們可以針對小文件的問題進行一些優化,HDFS本身提供了
解決方案:
1.Hadoop Archive/HAR:將小文件打包成大文件。
2.SEQUENCEFILE格式:將大量小文件壓縮成一個SEQUENCEFILE文件。
3.CombineFileInputFormat:在map和reduce處理之前組合小文件。
4.HDFS Federation:HDFS聯盟,使用多個namenode節點管理文件。
除此之外,我們還可以通過設置hive的參數來合併小文件。
1.輸入階段合併
需要更改Hive的輸入文件格式即參hive.input.format
默認值是org.apache.hadoop.hive.ql.io.HiveInputFormat
我們改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
這樣比起上面對mapper數的調整,會多出兩個參數,分別是mapred.min.split.size.per.node和mapred.min.split.size.per.rack,含義是單節點和單機架上的最小split大小。如果發現有split大小小於這兩個值(默認都是100MB),則會進行合併。具體邏輯可以參看Hive源碼中的對應類。
2.輸出階段合併
直接將hive.merge.mapfiles和hive.merge.mapredfiles都設為true即可,前者表示將map-only任務的輸出合併,後者表示將map-reduce任務的輸出合併,Hive會額外啟動一個mr作業將輸出的小文件合併成大文件。
另外,hive.merge.size.per.task可以指定每個task輸出後合併文件大小的期望值,hive.merge.size.smallfiles.avgsize可以指定所有輸出文件大小的均值閾值,默認值都是1GB。如果平均大小不足的話,就會另外啟動一個任務來進行合併。
2.2表的存儲格式
通過InputFormat和OutputFormat可以看出表的存儲格式是TEXT類型,Hive支持TEXTFILE, SEQUENCEFILE, AVRO, RCFILE, ORC,以及PARQUET文件格式,可以通過兩種方式指定表的文件格式:
1.CREATE TABLE … STORE AS :在建表時指定文件格式,默認是TEXTFILE
2.ALTER TABLE … [PARTITION partition_spec] SET FILEFORMAT :修改具體表的文件格式。
如果要改變創建表的默認文件格式,可以使用set hive.default.fileformat=進行配置,適用於所有表。
同時也可以使用set hive.default.fileformat.managed =進行配置,僅適用於內部表或外部表。
擴展:不同存儲方式的情況
TEXT, SEQUENCE和 AVRO文件是面向行的文件存儲格式,不是最佳的文件格式,因為即便只查詢一列數據,使用這些存儲格式的表也需要讀取完整的一行數據。另一方面,面向列的存儲格式(RCFILE, ORC, PARQUET)可以很好地解決上面的問題。
關於每種文件格式的說明,如下:
1.TEXTFILE
創建表時的默認文件格式,數據被存儲成文本格式。文本文件可以被分割和並行處理,也可以使用壓縮,比如GZip、LZO或者Snappy。然而大部分的壓縮文件不支持分割和並行處理,會造成一個作業只有一個mapper去處理數據,使用壓縮的文本文件要確保文件不要過大,一般接近兩個HDFS塊的大小。
2.SEQUENCEFILE
key/value對的二進制存儲格式,sequence文件的優勢是比文本格式更好壓縮,sequence文件可以被壓縮成塊級別的記錄,塊級別的壓縮是一個很好的壓縮比例。如果使用塊壓縮,需要使用下面的配置:
set hive.exec.compress.output=true;
set io.seqfile.compression.type=BLOCK;
1
2
3.AVRO
二進制格式文件,除此之外,avro也是一個序列化和反序列化的框架。avro提供了具體的數據schema。
4.RCFILE
全稱是Record Columnar File,首先將表分為幾個行組,對每個行組內的數據進行按列存儲,每一列的數據都是分開存儲,即先水平劃分,再垂直劃分。
5.ORC
全稱是Optimized Row Columnar,從hive0.11版本開始支持,ORC格式是RCFILE格式的一種優化的格式,提供了更大的默認塊(256M)
6.PARQUET
另外一種列式存儲的文件格式,與ORC非常類似,與ORC相比,Parquet格式支持的生態更廣,比如低版本的impala不支持ORC格式。
配置同樣數據同樣字段的兩張表,以常見的TEXT行存儲和ORC列存儲兩種存儲方式為例,對比執行速度。
總結:
從上圖中可以看出列存儲在對指定列進行查詢時,速度更快,建議在建表時設置列存儲的存儲方式。
2.3 表的壓縮
對Hive表進行壓縮是常見的優化手段,一些存儲方式自帶壓縮選擇,比如SEQUENCEFILE支持三種壓縮選擇:NONE,RECORD,BLOCK。Record壓縮率低,一般建議使用BLOCK壓縮。
ORC支持三種壓縮選擇:NONE,ZLIB,SNAPPY。我們以TEXT存儲方式和ORC存儲方式為例,查看錶的壓縮情況。
配置同樣數據同樣字段的四張表,一張TEXT存儲方式,另外三張分別是默認壓縮方式的ORC存儲、SNAPPY壓縮方式的ORC存儲和NONE壓縮方式的ORC存儲,查看在hdfs上的存儲情況:
總結:
可以看到ORC存儲方式將數據存放為兩個block,默認壓縮大小加起來134.69M,SNAPPY壓縮大小加起來196.67M,NONE壓縮大小加起來247.55M。
TEXT存儲方式的文件大小為366.58M,且默認block兩種存儲方式分別為256M和128M。
ORC默認的壓縮方式比SNAPPY壓縮得到的文件還小,原因是ORZ默認的ZLIB壓縮方式採用的是deflate壓縮算法,比Snappy壓縮算法得到的壓縮比高,壓縮的文件更小。
ORC不同壓縮方式之間的執行速度,經過多次測試發現三種壓縮方式的執行速度差不多,所以建議採用ORC默認的存儲方式進行存儲數據。
2.4分桶分區
Num Buckets表示桶的數量,我們可以通過分桶和分區操作對Hive表進行優化。
對於一張較大的表,可以將它設計成分區表,如果不設置成分區表,數據是全盤掃描的,設置成分區表後,查詢時只在指定的分區中進行數據掃描,提升查詢效率。要注意儘量避免多級分區,一般二級分區足夠使用。常見的分區字段:
1.日期或者時間,比如year、month、day或者hour,當表中存在時間或者日期字段時,可以使用些字段。
2.地理位置,比如國家、省份、城市等。
3.業務邏輯,比如部門、銷售區域、客戶等等。
與分區表類似,分桶表的組織方式是將HDFS上的一張大表文件分割成多個文件。
分桶是相對分區進行更細粒度的劃分,分桶將整個數據內容按照分桶字段屬性值得hash值進行區分,分桶可以加快數據採樣,也可以提升join的性能(join的字段是分桶字段),因為分桶可以確保某個key對應的數據在一個特定的桶內(文件),所以巧妙地選擇分桶字段可以大幅度提升join的性能。
通常情況下,分桶字段可以選擇經常用在過濾操作或者join操作的字段。
創建分桶表
create table test_user_bucket(idint,namestring,codestring,code_idstring) clustered by(id) into 3 buckets ROW FORMAT DELIMITED FIELDS TERMINATED BY',';
查看描述信息
DESCRIBE FORMATTED test_user_bucket
同樣的數據查看普通表和分桶表查詢效率
普通表是全表掃描,分桶表在按照分桶字段的hash值分桶後,根據join字段或者where過濾字段在特定的桶中進行掃描,效率提升。
本次優化主要建表配置參數方面對Hive優化進行講解,這是Hive優化的第一步,正如大多數據庫一樣,完整的調優必定還包括模型設計、引擎調優,關於這部分的內容請關注後續連載。