數倉特征:面向主題,集成,非易失的,時變。數據倉庫是在數據庫已經大量存在的情況下,為了進一步挖掘數據資源、為了決策需要而產生的,不是所謂的“大型數據庫”。
數據庫與數據倉庫的區別(OLTP 與 OLAP 的區別)
操作型處理,叫聯機事務處理 OLTP(On-Line Transaction Processing,),也可以稱面向交易的處理系統,它是針對具體業務在數據庫聯機的日常操作,通常對少數記錄進行查詢、修改。用戶較為關心操作的響應時間、數據的安全性、完整性和並發支持的用戶數等問題。傳統的數據庫系統作為數據管理的主要手段,主要用於操作型處理。
分析型處理,叫聯機分析處理 OLAP(On-Line Analytical Processing)一般針對某些主題的歷史數據進行分析,支持管理決策。
ETL:抽取 Extra, 轉化 Transfer, 裝載 Load。
為什么要對數倉分層?
分層:Ods、Dw、Dm、Ads
用空間換時間,通過大量的預處理來提升應用系統的用戶體驗(效率),因此數據倉庫會存在大量冗余的數據;不分層的話,如果源業務系統的業務規則發生變化將會影響整個數據清洗過程,工作量巨大。
數倉元數據管理
元數據(Meta Date), 主要記錄數據倉庫中模型的定義、各層級間的映射關系、監控數據倉庫的數據狀態及 ETL 的任務運行狀態。可分為技術元數據和業務元數據。
元數據不僅定義了數據倉庫中數據的模式、來源、抽取和轉換規則等,而且是整個數據倉庫系統運行的基礎,元數據把數據倉庫系統中各個松散的組件聯系起來,組成了一個有機的整體。
Hive 是基於 Hadoop 的一個數據倉庫工具,可以將結構化的數據文件映射為一張數據庫表,並提供類 SQL 查詢功能。 本質是將 SQL 轉換為 MapReduce 程序。利用HDFS 存儲數據,利用 MapReduce 查詢分析數據。

組件:用戶接口,元數據存儲mysql / derby,解釋、編譯、優化、執行器。
與數據庫的區別
- 數據存儲位置不同:Hive存儲在HDFS中,數據庫存儲在塊設備或本地文件
- 數據更新:數倉一般不改寫數據,數據庫增刪改查
- 執行延遲:Hive延遲高, mysql延遲低, 只有大規模數據時Hive並行計算的優點才會體現
- 數據規模:Hive大規模計算,數據庫規模較小
三種配置模式(本地模式、遠程模式與mysql是否在遠程無關!!!)
- 內嵌模式:使用的是內嵌的Derby數據庫來存儲元數據,也不需要額外起Metastore服務。
- 本地模式:
本地模式采用外部數據庫來存儲元數據,目前支持的數據庫有:MySQL、Postgres、Oracle、MS SQL Server.
不需要單獨起metastore服務,用的是跟hive在同一個進程里的metastore服務。也就是說當你啟動一個hive 服務,里面默認會幫我們啟動一個metastore服務。hive根據hive.metastore.uris 參數值來判斷,如果為空,則為本地模式。
缺點:每啟動一次hive服務,都內置啟動了一個metastore。本地模式下hive的配置主需要指定mysql的相關信息即可。(ConnectionURL)

- 遠程模式:
需要單獨起metastore服務,然后每個客戶端都在配置文件里配置連接到該metastore服務。遠程模式的metastore服務和hive運行在不同的進程里。
在生產環境中,建議用遠程模式來配置Hive Metastore。其他依賴hive的軟件都可以通過Metastore訪問hive。
遠程模式下,需要配置hive.metastore.uris 參數來指定metastore服務運行的機器ip和端口,並且需要單獨手動啟動metastore服務。

數據模型
- db(庫):在 hdfs 中表現為 hive.metastore.warehouse.dir 目錄下一個文件夾
- table(內部表):在 hdfs 中表現所屬 db 目錄下一個文件夾,當我們刪除一個內部表時,Hive也會刪除這個表中數據。內部表不適合和其他工具共享數據。
- external table(外部表):數據存放位置可以在 HDFS 任意指定路徑 ,刪除該表並不會刪除掉原始數據,刪除的是表的元數據
- partition(分區):在 hdfs 中表現為 table 目錄下的子目錄
DDL操作:
1 create table t_user_part(id int,name string,country string) 2 partitioned by (guojia string) 3 row format delimited fields terminated by ',' ; 4 --注意順序問題 5 --分區的字段不能是表當中的字段 6 7 load data local inpath './root/4.txt' 8 into table t_user_part partition (guojia='usa'); 9 10 load data local inpath '/root/5.txt' 11 into table t_user_part partition (guojia='china'); 12 --將數據加載到哪個文件夾中 13 14 --多級分區 15 create table t_order(id int,pid int,price double) 16 partitioned by (year string,month string,day string) 17 row format delimited fields terminated by ',' ; 18 19 load data local inpath '/root/5.txt' 20 into table t_order partition (year='2019',month='09',day='18'); 21 22 load data local inpath '/root/4.txt' 23 into table t_order partition (year='2019',month='09',day='18'); 24 25 ALTER TABLE t_user_part ADD PARTITION (guojia='riben') 26 location '/user/hive/warehouse/hadoop32.db/t_user_part/guojia=riben'; 27 --一次添加一個分區 28 29 ALTER TABLE order ADD 30 PARTITION (year='2018', month='09',day="20") 31 location'/user/hive/warehouse/hadoop32.db/t_order' 32 PARTITION (year='2019', month='09',day="20") 33 location'/user/hive/warehouse/hadoop32.db/t_order'; 34 --一次添加多個分區 35 36 --刪除分區 37 ALTER TABLE t_user_part DROP IF EXISTS PARTITION (guojia=riben); 38 39 --查看分區 40 show partitions table_name; 41 42 show formatted table_name;
- bucket(分桶):在 hdfs 中表現為同一個表目錄下根據 hash 散列之后的多個文件 ,采用對列值哈希,然后除以桶的個數求余的方式決定該條記錄存放在哪個桶當中
DDL操作:
1 create table stu_buck(Sno string,Sname string, 2 Sbrithday string, Sex string) 3 clustered by(Sno) 4 into 4 buckets 5 row format delimited fields terminated by '\t'; 6 --clustered by 根據哪個字段去分桶,這個字段在表中一定存在 7 --into N buckets 分多少個文件 8 --如果該分桶字段是string,會根據字符串的hashcode % bucketsNum 9 --如果該分桶字段是數值類型,數值 % bucketsNum 10 11 create table student(Sno string,Sname string, 12 Sbrithday string, Sex string) 13 row format delimited fields terminated by '\t'; 14 --insert+select 15 insert overwrite table stu_buck select * from student 16 cluster by(Sno); 17 --默認不讓直接使用分桶表
DML操作
1 --load加載 推薦方式,最常見 (分桶表是不支持load) 2 load data local inpath '/root/hivedata/students.txt' 3 overwrite into table student; 4 --加載本地數據到表對應的路徑下 5 --local表明是本地還是hdfs 6 --overwrite表示覆蓋操作(慎用) 7 8 load data inpath '/stu' into table student_ext; 9 --加載hdfs上的文件到表對應的路徑下(追加) 10 11 --insert + select導入 12 --insert 主要是結合 select 查詢語句使用,將查詢結果插入到表中 13 insert overwrite table tablename1 14 [partition (partcol1=val1,partclo2=val2)] 15 select_statement1 from source_table 16 17 --多重插入 18 from source_table 19 insert overwrite table tablename1 20 [partition (partcol1=val1,partclo2=val2)] 21 select_statement1 22 insert overwrite table tablename2 23 [partition (partcol1=val1,partclo2=val2)] 24 select_statement2.. 25 26 --動態插入 substr(day,1,7) as month,day分區的虛擬字段 順序需要對應 27 insert overwrite table d_p_t partition (month,day) 28 select ip,substr(day,1,7) as month,day 29 from dynamic_partition_table; 30 31 --指定分隔符(復雜類型的數據表) 32 --表1(包含array字段類型) 33 --數據: zhangsan beijing,shanghai,tianjin,hangzhou 34 -- wangwu shanghai,chengdu,wuhan,haerbin 35 create table complex_array(name string, 36 work_locations array<string>) 37 row format delimited fields terminated by '\t' 38 collection items terminated by ','; 39 --collection items array集合分隔符 40 41 --表2(包含map字段類型) 42 create table t_map(id int,name string,hobby map<string,string>) 43 row format delimited 44 fields terminated by ',' 45 collection items terminated by '-' 46 map keys terminated by ':' ; 47 --map keys map中k-v分隔符 48 --數據:1,zhangsan,唱歌:非常喜歡-跳舞:喜歡-游泳:一般般 49 -- 2,lisi,打游戲:非常喜歡-籃球:不喜歡
DQL操作
4個By區別
Sort By:分區內有序,只保證每個 reducer 的輸出有序,不保證全局有序。
Order By:全局排序,只有一個Reducer;
Distrbute By:類似MR中Partition,進行分區,結合sort by使用。
Cluster By:當Distribute by和Sorts by字段相同時可以使用Cluster by方式。Cluster by除了具有Distribute by的功能外還兼具Sort by的功能。但是排序只能是升序排序,不能指定排序規則為ASC或者DESC。
如果 distribute 和 sort 的字段是同一個時,此時,cluster by = distribute by + sort by
Join
inner join 內連接,兩張表都滿足條件的數據
left join 左鏈接,以左表為主表,主表的數據都顯示
left semi join 顯示左表的數據部分(內連接)
參數的配置方式優先級別:依次增強
默認的配置(hive-default.xml),自定義的配置(hive-site.xml),shell命令行參數,session的命令行中進行設置
Shell命令行參數(常用) -e "sql" 可以跟上sql的字符串,-f file.sql 可以跟上sql腳本文件
-hiveconf <property = value> (參數配置,傳遞參數到腳本文件中)
-hivevar <key = value> (只能傳遞參數)
內置函數
查看系統自帶的函數:show functions;
顯示自帶的函數的用法:
#不詳細 desc function upper;
#詳細 desc function extended upper;
條件判斷函數:
CASE
語法 : CASE a WHEN b THEN c [WHEN d THEN e]* [ELSE f] END
返回值 : T
說明:如果 a 等於 b ,那么返回 c ;如果 a 等於 d ,那么返回 e ;否則返回 f
舉例:hive> Select case 100 when 50 then 'tom' when 100 then 'mary' else 'tim' end from dual;
mary
字符串連接函數:CONCAT
帶分隔符字符串連接函數:concat_ws
舉例:select concat_ws(',', 'abc', '123')
自定義函數
UDF(User-Defined-Function)普通函數 一進一出
繼承UDF 重載evaluate方法 打成jar包(胖包)上傳到服務器 將jar包添加到 hive 的 classpath hive>add jar /home/hadoop/udf.jar; 創建臨時函數與開發好的java class關聯 create temporary function tolowercase as 'cn.itcast.hive.UDF_Demo'; (不加temporary就是創建永久函數,需要使用drop手動刪除) 在hql中使用自定義的函數tolowercase ip Select tolowercase(name),age from t_test;
UDAF(User-Defined Aggregation Function)聚合函數 多進一出
UDAF是輸入多個數據行,產生一個數據行
用戶自定義的UDAF必須是繼承了UDAF,且內部包含多個實現了exec的靜態類
UDTF(User-Defined Table-Generating Functions)表生成函數 一進多出
繼承org.apache.hadoop.hive.ql.udf.generic.GenericUDTF, 實現initialize, process, close三個方法。 UDTF首先會調用initialize方法, 此方法返回UDTF的返回行的信息(返回個數,類型)。 初始化完成后,會調用process方法,真正的處理過程在process函數中, 在process中,每一次forward()調用產生一行; 如果產生多列可以將多個列的值放在一個數組中, 然后將該數組傳入到forward()函數。 最后close()方法調用,對需要清理的方法進行清理 把程序打成jar包 添加jar包:add jar /run/jar/udf_test.jar; 創建臨時函數: CREATE TEMPORARY FUNCTION explode_map AS 'cn.itcast.hive.udtf.ExplodeMap'; 銷毀臨時函數:hive> DROP TEMPORARY FUNCTION add_example; UDTF有兩種使用方法, 一種直接放到select后面(不可以添加其他字段使用,不可以嵌套調用, 不可以和group by/cluster by/distribute by/sort by一起使用) 一種和lateral view一起使用
lateral view(側視圖)與 explode函數
explode可以對數值類型為array,或者為map結構的進行分割處理
對array處理:將array每個元素單獨作為一行輸出
對map處理:將map中的元素作為一行輸出,key作為一列,value作為一列
一般情況下,直接使用即可,也可以根據需要結合lateral view 使用
lateral view為側視圖,意義是為了配合UDTF來使用,把某一行數據拆分成多行數據。不加lateral view的UDTF只能提取單個字段拆分,並不能塞回原來數據表中。
加上lateral view就可以將拆分的單個字段數據與原始表數據關聯上。在使用lateral view的時候需要指定視圖別名和生成的新列別名。
1 --select 字段1, 字段2, ... 2 --from tabelA lateral view UDTF(xxx) 視圖別名(虛擬表名) as a,b,c 3 --例如 4 select name,subview.* from test_message 5 lateral view explode(location) subview as lc;
行列轉換
1.多行轉多列
col1 col2 col3
a c 1
a d 2
a e 3
b c 4
b d 5
b e 6
現在要將其轉化為:
col1 c d e
a 1 2 3
b 4 5 6
此時需要使用到max(case … when … then … else 0 end),僅限於轉化的字段為數值類型且為正值的情況
1 select col1, 2 max(case col2 when 'c' then col3 else 0 end) as c, 3 max(case col2 when 'd' then col3 else 0 end) as d, 4 max(case col2 when 'e' then col3 else 0 end) as e 5 from row2col 6 group by col1;
2.多行轉單列(重要)
col1 col2 col3
a b 1
a b 2
a b 3
c d 4
c d 5
c d 6
將其轉化為:
col1 col2 col3
a b 1,2,3
c d 4,5,6
此時需要兩個內置的函數:
a)concat_ws(參數1,參數2),用於進行字符的拼接
參數1—指定分隔符
參數2—拼接的內容
b)collect_set(col3),它的主要作用是將某字段的值進行去重匯總,產生array類型字段,如果不想去重可用collect_list()
1 select collect_set(col3) from row2col_1; 2 --將col3的所有數據放到一個集合中(去重) 3 4 select collect_set(col3) from row2col_1 group by col1,col2; 5 --根據col1,col2進行分組,只有第一列和第二列都相同,認為是同一組 6 7 select col1,col2, collect_set(col3) from row2col_1 8 group by col1,col2; 9 --三列顯示,行轉列 10 11 select col1, col2, 12 concat_ws(',', collect_set(cast(col3 as string))) as col3 13 from row2col_1 14 group by col1, col2; 15 --cast(col3 as string)將第三列變成string類型 16 --因為concat_ws是對於字符串拼接
3.多列轉多行
col1 c d e
a 1 2 3
b 4 5 6
現要將其轉化為:
col1 col2 col3
a c 1
a d 2
a e 3
b c 4
b d 5
b e 6
這里需要使用union進行拼接。union 可以結合多個select語句 返回共同的結果集保證每個select語句返回的數據類型個數是一致的。
1 select col1, 'c' as col2, c as col3 from col2row 2 UNION 3 select col1, 'd' as col2, d as col3 from col2row 4 UNION 5 select col1, 'e' as col2, e as col3 from col2row 6 order by col1, col2;
4.單列轉多行(重要)
col1 col2 col3
a b 1,2,3
c d 4,5,6
現要將其轉化為:
col1 col2 col3
a c 1
a d 2
a e 3
b c 4
b d 5
b e 6
這里需要使用UDTF(表生成函數)explode(),該函數接受array類型的參數,其作用恰好與collect_set相反,實現將array類型數據行轉列。explode配合lateral view實現將某列數據拆分成多行。
1 select col1, col2, lv.col3 as col3 2 from col2row_2 3 lateral view explode(split(col3, ',')) lv as col3;
reflect函數
可以支持在 sql 中調用 java 中的自帶函數,秒殺一切 udf 函數
--例1 --使用 java.lang.Math 當中的 Max 求兩列當中的最大值 select reflect("java.lang.Math","max",col1,col2) from test_udf; --例2 --准備數據 test_udf2.txt java.lang.Math,min,1,2 java.lang.Math,max,2,3 --執行查詢 select reflect(class_name,method_name,col1,col2) from test_udf2;
json
什么叫json:原生的js對象
hive處理json數據總體來說有兩個方向的路走:
1. 將json以字符串的方式整個導入hive表,然后通過使用UDF函數解析已經導入到hive中的數據,比如使用lateral view json_tuple的方法,獲取所需要的列名
- get_json_object(string json_string,string path):第一個參數填寫json對象變量,第二個參數使用$表示json變量表示,每次只能返回一個數據項
1 select get_json_object(t.json,'$.id'), 2 get_json_object(t.json,'$.total_number') 3 from tmp_json_test t;
- json_tuple(string json_string,'屬性1','屬性2')
1 select json_tuple(json,'id','ids','total_number') 2 from tmp_json_test;
2. 在導入之前將json拆成各個字段,導入Hive表的數據是已經解析過的,這將需要使用地方放的SerDe
1 --從http:www.congiu.net/hive-json-serde/下載jar包 2 add jar 3 /root/hivedata/json-serde-1.3.7-jar-with-dependencies.jar; 4 5 create table tmp_json_array(id string, 6 ids array<string>,total_number int) 7 row format SERDE 'org.openx.data.jsonserde.JsonSerDe' 8 stored as textfile; 9 load data local inpath '/root/hivedata/json_test.txt' 10 overwrite into table tmp_json_array;
窗口函數
又叫 OLAP 函數/分析函數,兼具分組和排序功能
窗口函數最重要的關鍵字是
partition by 和 order by。
具體語法如下:over (partition by xxx order by xxx)
- 如果不指定 rows between,默認為從起點到當前行;
- 如果不指定 order by,則將分組內所有值累加;
- 關鍵是理解 rows between 含義,也叫做 window 子句:
- preceding:往前
- following:往后
- current row:當前行
- unbounded:起點
- unbounded preceding 表示從前面的起點
- unbounded following:表示到后面的終點
AVG,MIN,MAX,和 SUM 用法一樣。
例:
1 select cookieid,createtime,pv, 2 sum(pv) over(partition by cookieid order by createtime) as pv1 3 from itcast_t1; 4 --pv1: 分組內從起點到當前行的 pv 累積, 5 --如,11 號的 pv1=10 號的 pv+11 號的 pv, 12 號=10 號+11 號+12 6 7 select cookieid,createtime,pv, 8 sum(pv) over(partition by cookieid) as pv3 9 from itcast_t1; 10 --pv3: 分組內(cookie1)所有的 pv 累加 11 12 select cookieid,createtime,pv, 13 sum(pv) over(partition by cookieid 14 order by createtime 15 rows between 3 preceding and 1 following) as pv5 16 from itcast_t1; 17 --pv5: 分組內當前行+往前 3 行+往后 1 行, 18 --如,14 號=11 號+12 號+13 號+14 號+15 號=5+7+3+2+4=21 19 20 select cookieid,createtime,pv, 21 sum(pv) over(partition by cookieid 22 order by createtime rows between current row and 23 unbounded following) as pv6 24 from itcast_t1; 25 --pv6: 分組內當前行+往后所有行, 26 --如,13 號=13 號+14 號+15 號+16 號=3+2+4+4=13, 27 --14 號=14 號+15 號+16 號=2+4+4=10
- ROW_NUMBER() 從 1 開始,按照順序,生成分組內記錄的序列。 1 2 3 4
- RANK() 生成數據項在分組中的排名,排名相等會在名次中留下空位 。1 2 2 4
- DENSE_RANK()生成數據項在分組中的排名,排名相等在名次中不會留下空位。1 2 2 3
1 SELECT 2 cookieid, 3 createtime, 4 pv, 5 RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn1, 6 DENSE_RANK() OVER(PARTITION BY cookieid ORDER BY pv desc) AS rn2, 7 ROW_NUMBER() OVER(PARTITION BY cookieid ORDER BY pv DESC) AS rn3 8 FROM itcast_t2 WHERE cookieid = 'cookie1';
NTILE
有時會有這樣的需求:如果數據排序后分為三部分,業務人員只關心其中的一部分,如何將這中間的三分之一數據拿出來呢?NTILE 函數即可以滿足。 可以看成是:把有序的數據集合平均分配到指定的數量(num)個桶中, 將桶號分配給每一行。如果不能平均分配,則優先分配較小編號的桶,並且各個
桶中能放的行數最多相差 1。 然后可以根據桶號,選取前或后 n 分之幾的數據。數據會完整展示出來,只是給相應的數據打標簽;具體要取幾分之幾的數據,需要再嵌套一層根據標簽取出。
1 SELECT * FROM 2 (SELECT 3 cookieid, 4 createtime, 5 pv, 6 NTILE(2) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn1, 7 NTILE(3) OVER(PARTITION BY cookieid ORDER BY createtime) AS rn2, 8 NTILE(4) OVER(ORDER BY createtime) AS rn3 9 FROM itcast_t2 ORDER BY cookieid,createtime) temp 10 WHERE cookieid = 'cookie2' AND rn2 = 2;
Lag(col, n)往前n行
Lead(col, n)往后n行
數據壓縮
優缺點
優點: 減少存儲磁盤空間,降低單節點的磁盤 IO。 由於壓縮后的數據占用的帶寬更少,因此可以快數據在 Hadoop 集群流動的速度,減少網絡傳輸帶寬。
缺點: 需要花費額外的時間/CPU 做壓縮和解壓縮計算
MR哪些過程可以設置壓縮?
需要分析處理的數據在進入map 前可以壓縮,然后解壓處理,map 處理完成后的輸出可以壓縮,這樣可以減少網絡 I/O(reduce 通常和 map 不在同一節點上),reduce 拷貝壓縮的數據后進行解壓,處理完成后可以壓縮存儲在 hdfs 上,以減少磁盤占用量。
數據存儲格式
- 行式存儲
優點: 相關的數據是保存在一起,比較符合面向對象的思維,因為一行數據就是一條記錄,這種存儲格式比較方便進行 INSERT/UPDATE 操作
缺點: 如果查詢只涉及某幾個列,它會把整行數據都讀取出來,不能跳過不必要的列讀取。當然數據比較少,一般沒啥問題,如果數據量比較大就比較影響性能 由於每一行中,列的數據類型不一致,導致不容易獲得一個極高的壓縮比,也就是空間利用率不高 不是所有的列都適合作為索引
- 列式存儲
優點: 查詢時,只有涉及到的列才會被查詢,不會把所有列都查詢出來,即可以跳過不必要的列查詢; 高效的壓縮率,不僅節省儲存空間也節省計算內存和 CPU。任何列可以作為索引;
缺點: INSERT/UPDATE 很麻煩或者不方便; 不適合掃描小量的數據
Hive 支持的存儲數的格式主要有:TEXTFILE(行式存儲) 、SEQUENCEFILE(行式存儲)、ORC(列式存儲)、PARQUET(列式存儲)。

TEXTFILE,行式存儲,但使用這種方式,hive 不會對數據進行切分,從而無法對數據進行並行操作
ORC,列式存儲,它並不是一個單純的列式存儲格式,仍然是首先根據行組分割整個表,在每一個行組內進行按列存儲
優點: ORC 是列式存儲,有多種文件壓縮方式,並且有着很高的壓縮比。 文件是可切分(Split)的。因此,在 Hive 中使用 ORC 作為表的文件存儲格式,不僅節省 HDFS 存儲資源,查詢任務的輸入數據量減少,使用的 MapTask 也就減少了。 ORC 可以支持復雜的數據結構(比如 Map 等)。ORC 文件也是以二進制方式存儲的,所以是不可以直接讀取,ORC 文件也是自解析的。
一個 ORC 文件可以分為若干個 Stripe,一個 Stripe可以分為三個部分:
- indexData:某些列的索引數據。一個輕量級的 index,默認是每隔 1W 行做一個索引。這里做的索引只是記錄某行的各字段在 Row Data 中的 offset
- rowData :真正的數據存儲。,先取部分行,然后對這些行按列進行存儲。對每個列進行了編碼,分成多個 Stream 來存儲。
- StripFooter:存放各個stripe 的元數據信息。每個文件有一個 File Footer,這里面存的是每個 Stripe 的行數,每個 Column的數據類型信息等;每個文件的尾部是一個 PostScript,這里面記錄了整個文件的壓縮類型以及 FileFooter 的長度信息等。在讀取文件時,會 seek 到文件尾部讀PostScript,從里面解析到 File Footer 長度,再讀 FileFooter,從里面解析到各個Stripe 信息,再讀各個 Stripe,即從后往前讀。

PARQUET,列式存儲,是面向分析型業務的列式存儲格式。Parquet 文件是以二進制方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數據和元數據,因此 Parquet 格式文件是自解析的。 通常情況下,在存儲Parquet數據的時候會按照Block大小設置行組的大小,由於一般情況下每一個 Mapper 任務處理數據的最小單位是一個 Block,這樣可以把每一個行組由一個 Mapper 任務處理,增大任務執行並行度。
存儲格式總結
ORC存儲文件默認采用 ZLIB 壓縮。比 snappy 壓縮的小。 在實際的項目開發當中,hive 表的數據存儲格式一般選擇:orc 或 parquet。壓縮方式一般選擇 snappy。
存儲文件的壓縮比總結: ORC > Parquet > textFile
存儲文件查詢速度三種差不多
優化
0. 分區分桶技術,行列過濾
1. Fetch 抓取機制
在 hive-default.xml.template 文件中 hive.fetch.task.conversion 默認是 more,老版本 hive 默認是 minimal,該屬性修改為 more 以后,在全局查找、字段查找、limit 查找等都不走 mapreduce。
2. mapreduce 本地模式
mapreduce可以使用本地模擬環境運行,此時就不是分布式執行的程序,但是針對小文件小數據處理特別有效果。用戶可以通過設置 hive.exec.mode.local.auto 的值為 true,來讓 Hive 在適當的時候自動啟動這個優化。
3. join優化
1)map join 在 Reduce 階段完成 join。容易發生數據傾斜。可以用 MapJoin 把小表全部加載到內存在 map 端進行 join,避免 reducer處理。 在實際使用中,只要根據業務把握住小表的閾值標准即可,hive 會自動幫我們完成 mapjoin,提高執行的效率。
2)大表 join 大表
空key過濾,key對應的數據為異常數據,例如空,可進行過濾
空key轉換,key對應的數據有用,必須進行join,通過 hive 的 rand 函數,隨記的給每一個為空的 id 賦上一個隨機值,這樣就不會造成數據傾斜。
3)大小表,小大表join 在當下的 hive 版本中,大表 join 小表或者小表 join 大表,就算是關閉 map端 join 的情況下,基本上沒有區別了(hive 為了解決數據傾斜的問題,會自動進行過濾) 。
4. group by 優化—map 端聚合
很多聚合操作都可以先在 Map 端進行部分聚合,最后在 Reduce 端得出最終結果。
1)是否在 Map 端進行聚合,默認為 True set hive.map.aggr = true;
2)在 Map 端進行聚合操作的條目數目 set hive.groupby.mapaggr.checkinterval = 100000;
3)有數據傾斜的時候進行負載均衡(默認是 false) set hive.groupby.skewindata = true;
5. 數據傾斜問題
1)調整mapTask個數
在Map執行前合並小文件,減少Map數:CombineHiveInputFormat具有對小文件進行合並的功能(系統默認的格式)。HiveInputFormat沒有對小文件合並功能。
當 input 的文件都很大,任務邏輯復雜,map 執行非常慢的時候,可以考慮增加 Map 數
2)調整reduceTask個數,reduce 個數並不是越多越好
1)過多的啟動和初始化 reduce 也會消耗時間和資源;
2)另外,有多少reduce,就會有多少輸出文件,如果生成很多個小文件,那么如果這些小文件作為下一個任務的輸入,則也會出現小文件過多的問題; 在設置 reduce 個數的時候也需要考慮這兩個原則:處理大數據量利用合適的 reduce 數;使單個 reduce 任務處理數據量大小要合適。
6. 了解執行計划—explain
7. 並行執行機制
通過設置參數 hive.exec.parallel 值為true,就可以開啟並發執行。
8. 嚴格模式
通過設置屬性 hive.mapred.mode 值為默認是非嚴格模式 nonstrict 。開啟嚴格模式需要修改 hive.mapred.mode 值為 strict,開啟嚴格模式可以禁止 3 種類型的查詢。
1)對於分區表,除非 where 語句中含有分區字段過濾條件來限制范圍,否
則不允許執行。用戶不允許掃描所有分區。
2)對於使用了 order by 語句的查詢,要求必須使用 limit 語句。因為 order
by 為了執行排序過程會將所有的結果數據分發到同一個 Reducer 中進行處理,
3)限制笛卡爾積的查詢。
9. jvm 重用機制
JVM 重用可以使得 JVM 實例在同一個 job 中重新使用 N 次,這個功能的缺點是,開啟 JVM 重用將一直占用使用到的 task 插槽,以便進行重用,直到任務完成后才能釋放。
10. 推測執行機制
推測出“拖后腿”的任務,並為這樣的任務啟動一個備份任務,讓該任務與原始任務同時處理同一份數據,並最終選用最先成功運行完成任務的計算結果作為最終結果。