數倉特徵:面向主題,整合,非易失的,時變。資料倉儲是在資料庫已經大量存在的情況下,為了進一步挖掘資料資源、為了決策需要而產生的,不是所謂的“大型資料庫”。
資料庫與資料倉儲的區別(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. 推測執行機制
推測出“拖後腿”的任務,併為這樣的任務啟動一個備份任務,讓該任務與原始任務同時處理同一份資料,並最終選用最先成功執行完成任務的計算結果作為最終結果。