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列存儲兩種存儲方式為例,對比執行速度。
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存儲方式
SNAPPY壓縮的ORC存儲方式
NONE壓縮的ORC存儲方式
可以看到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
多出了如下資訊
檢視該表的hdfs
同樣的資料檢視普通表和分桶表查詢效率
普通表
分桶表
普通表是全表掃描,分桶表在按照分桶字段的hash值分桶後,根據join字段或者where過濾字段在特定的桶中進行掃描,效率提升。
本次優化主要建表配置參數方面對Hive優化進行講解,這是Hive優化的第一步,正如大多資料庫一樣,完整的調優必定還包括模型設計、引擎調優,關于這部分的内容請關注後續連載。