Hive 高頻考點講解
1 Hive
Hive 是 FaceBook 開源的一款基於 Hadoop 數據倉庫工具,它可以將結構化的數據文件映射爲一張表,並提供類 SQL 查詢功能。
The Apache Hive ™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL 。
1.1 Hive 優缺點
1.1.1 優點
-
操作接口採用類 SQL 語法,提供快速開發的能力(簡單、容易上手)。
-
避免了去寫 MapReduce,減少開發人員的學習成本。
-
Hive 的執行延遲比較高,因此 Hive 常用於數據分析,對實時性要求不高的場合。
-
Hive 優勢在於處理大數據,對於處理小數據沒有優勢,因爲 Hive 的執行延遲比較高。
-
Hive 支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數。
1.1.2 缺點
-
Hive 的 HQL 表達能力有限,無法表達迭代式算法,不擅長數據挖掘方面。
-
Hive 的效率比較低,Hive 自動生成的 MapReduce 作業,通常情況下不夠智能化。
-
Hive 查詢無法做到跟 MySQL 一樣毫秒返回。
1.2 Hive 跟 MySQL 比較
1.2.1 對比
Hive 採用了類 SQL 的查詢語言 HQL(Hive Query Language),因此很容易將 Hive 理解爲數據庫。其實從結構上來看,Hive 和數據庫除了擁有類似的查詢語言,再無類似之處。本文將從多個方面來闡述 Hive 和數據庫的差異。數據庫可以用在 Online 的應用中,但是 Hive 是爲數據倉庫而設計的,清楚這一點,有助於從應用角度理解 Hive 的特性。
1.2.2 Hive 不支持那些
-
支持等值查詢,不支持非等值連接
-
支持 and 多條件過濾,不支持 or 多條件過濾。
-
不支持 update 跟 delete。
1.3 Hive 底層
Hive 底層是 MapReduce 計算框架,Hive 只是將通讀性強且容易編程的 SQL 語句通過 Hive 軟件轉換成 MapReduce 程序在集羣上執行,Hive 可以看做 MapReduce 客戶端。操作的數據還是存儲在 HDFS 上的,而用戶定義的表結構等元信息被存儲到 MySQL 上了。以前要寫八股文 MapReduce 程序,現在只需要 HQL 查詢就可!
Hive 整體框架
- 用戶接口 Client
CLI(hive shell)、JDBC/ODBC(java 訪問 hive)、WEBUI(瀏覽器訪問 hive)
元數據 Metastore
元數據包括 表名、表所屬的數據庫(默認是 default)、表的擁有者、列 / 分區字段、表的類型(是否是外部表)、表的數據所在目錄等。
默認存儲在自帶的 derby 數據庫中 (單客戶連接),推薦使用 MySQL 存儲 Metastore。
Hadoop
使用 HDFS 進行存儲,使用 MapReduce 進行計算。
- 驅動器 Driver
解析器 SQL Parser:將 SQL 字符串轉換成抽象語法樹 AST,這一步一般都用第三方工具庫完成,比如 antlr;對 AST 進行語法分析,比如表是否存在、字段是否存在、SQL 語義是否有誤。
編譯器 Physical Plan:將 AST 編譯生成邏輯執行計劃。
優化器 Query Optimizer:對邏輯執行計劃進行優化。
執行器 Execution:把邏輯執行計劃轉換成可以運行的物理計劃。對於 Hive 來說就是 MR/Spark。
HQL 執行流程
不要把 Hive 想的多麼神祕,你可以用簡單的 load 方式將數據加載到創建的表裏,也可以直接用 hadoop 指令將數據放入到指定目錄,這兩種方式都可以直接讓你通過 SQL 查詢到數據。
1.4 HQL 底層執行舉例
1.4.1 Join
Join 流程
1.4.2 group by
group by 流程
1.4.3 distinct
distinct 流程
2 開窗函數
有時想要同時顯示聚集前後的數據,這時引入了窗口函數,在 SQL 處理中,窗口函數都是最後一步執行
,而且僅位於 Order by 字句之前。
2.1 數據準備
name,orderdate,cost
jack,2017-01-01,10
tony,2017-01-02,15
jack,2017-02-03,23
tony,2017-01-04,29
jack,2017-01-05,46
jack,2017-04-06,42
tony,2017-01-07,50
jack,2017-01-08,55
mart,2017-04-08,62
mart,2017-04-09,68
neil,2017-05-10,12
mart,2017-04-11,75
neil,2017-06-12,80
mart,2017-04-13,94
建表 導數據
create table business(
name string,
orderdate string,
cost int
) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
load data local inpath "/opt/module/datas/business.txt" into table business;
2.2 用法
相關函數說明
-
OVER():指定分析函數工作的數據窗口大小,這個數據窗口大小可能會隨着行的變而變化
-
CURRENT ROW:當前行
-
n PRECEDING:往前 n 行數據
-
n FOLLOWING:往後 n 行數據
-
UNBOUNDED:起點,UNBOUNDED PRECEDING 表示從前面的起點, UNBOUNDED FOLLOWING 表示到後面的終點
上面寫 over 裏面,下面寫 over 前面。
-
LAG(col,n):往前
第
n 行數據 -
LEAD(col,n):往後
第
n 行數據 -
NTILE(n):把有序分區中的行分發到指定數據的組中,各個組有編號,編號從 1 開始,對於每一行,NTILE 返回此行所屬的組的編號。注意:n 必須爲 int 類型。
2.3 開窗函數 demo
- 查詢在 2017 年 4 月份購買過的顧客及總人數
select name,count(*) over() from business where substring(orderdate,1,7) = '2017-04' group by name;
結果:
mart 2
jack 2
- 查詢顧客的購買明細及月購買總額
select name,orderdate,cost,sum(cost) over(partition by month(orderdate))
from business;
解釋:按照月劃分數據 然後統計這個月的cost總和
jack 2017-01-01 10 205
jack 2017-01-08 55 205
tony 2017-01-07 50 205
jack 2017-01-05 46 205
tony 2017-01-04 29 205
tony 2017-01-02 15 205
jack 2017-02-03 23 23
mart 2017-04-13 94 341
jack 2017-04-06 42 341
mart 2017-04-11 75 341
mart 2017-04-09 68 341
mart 2017-04-08 62 341
neil 2017-05-10 12 12
neil 2017-06-12 80 80
- 查看顧客上次的購買時間
select name,orderdate,cost,
lag(orderdate,1,'defaulttime') over(partition by name order by orderdate ) as time1,
lag(orderdate,2,'defaulttime') over (partition by name order by orderdate) as time2 from business;
結果 :
姓名 日期 價格 前一天日期 前兩天日期
jack 2017-01-01 10 defaulttime defaulttime
jack 2017-01-05 46 2017-01-01 defaulttime
jack 2017-01-08 55 2017-01-05 2017-01-01
jack 2017-02-03 23 2017-01-08 2017-01-05
jack 2017-04-06 42 2017-02-03 2017-01-08
mart 2017-04-08 62 defaulttime defaulttime
mart 2017-04-09 68 2017-04-08 defaulttime
mart 2017-04-11 75 2017-04-09 2017-04-08
mart 2017-04-13 94 2017-04-11 2017-04-09
neil 2017-05-10 12 defaulttime defaulttime
neil 2017-06-12 80 2017-05-10 defaulttime
tony 2017-01-02 15 defaulttime defaulttime
tony 2017-01-04 29 2017-01-02 defaulttime
tony 2017-01-07 50 2017-01-04 2017-01-02
- 查詢前 20% 時間的訂單信息
select * from (
select name,orderdate,cost, ntile(5) over(order by orderdate) sorted from business ) t where sorted = 1;
結果 :
jack 2017-01-01 10 1
tony 2017-01-02 15 1
tony 2017-01-04 29 1
jack 2017-01-05 46 2
tony 2017-01-07 50 2
jack 2017-01-08 55 2
jack 2017-02-03 23 3
jack 2017-04-06 42 3
mart 2017-04-08 62 3
mart 2017-04-09 68 4
mart 2017-04-11 75 4
mart 2017-04-13 94 4
neil 2017-05-10 12 5
neil 2017-06-12 80 5
以下實驗均關注最後一列
- 所有行相加
select name,orderdate,cost,sum(cost) over() as sample1 from business;
結果 :
mart 2017-04-13 94 661
neil 2017-06-12 80 661
mart 2017-04-11 75 661
neil 2017-05-10 12 661
mart 2017-04-09 68 661
2. 按 name 分組,組內數據相加
select name,orderdate,cost,sum(cost) over(partition by name) as sample2
from business;
結果 :
jack 2017-01-05 46 176
jack 2017-01-08 55 176
jack 2017-01-01 10 176
jack 2017-04-06 42 176
jack 2017-02-03 23 176
...
tony 2017-01-04 29 94
tony 2017-01-02 15 94
tony 2017-01-07 50 94
- 按 name 分組,組內數據累加
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate) as sample3
from business;
跟下面類似
select name,orderdate,cost,
sum(cost) over(distribute by name sort by orderdate) as sample3
from business;
jack 2017-01-01 10 10
jack 2017-01-05 46 56
jack 2017-01-08 55 111
jack 2017-02-03 23 134
jack 2017-04-06 42 176
...
- 和 sample3 一樣, 由起點到當前行的聚合
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
between UNBOUNDED PRECEDING and current row ) as sample4
from business;
結果 :
jack 2017-01-01 10 10
jack 2017-01-05 46 56
jack 2017-01-08 55 111
jack 2017-02-03 23 134
jack 2017-04-06 42 176
...
- 當前行和前面一行做聚合
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
between 1 PRECEDING and current row) as sample5
from business;
結果 :
jack 2017-01-01 10 10
jack 2017-01-05 46 56 = 46 + 10
jack 2017-01-08 55 101 = 44 + 46
jack 2017-02-03 23 78 = 23 + 55
jack 2017-04-06 42 65 = 42 + 23
...
tony 2017-01-02 15 15
tony 2017-01-04 29 44
tony 2017-01-07 50 79
- 當前行和前邊一行及後面一行
select name,orderdate,cost,
sum(cost) over(partition by name order by orderdate rows
between 1 PRECEDING AND 1 FOLLOWING ) as sample6
from business;
結果 :
jack 2017-01-01 10 56 = 10 + 46
jack 2017-01-05 46 111 = 46 + 10 + 55
jack 2017-01-08 55 124 = 55 + 46 + 23
jack 2017-02-03 23 120 = 23 + 55 + 42
jack 2017-04-06 42 65 = 42 + 23
...
tony 2017-01-02 15 44
tony 2017-01-04 29 94
tony 2017-01-07 50 79
- 當前行及後面所有行
select name,orderdate,cost,sum(cost) over(partition by name order by orderdate rows between current row and UNBOUNDED FOLLOWING ) as sample7 from business;
結果 :
jack 2017-01-01 10 176 = 10 + 46 + 55 + 23 + 42
jack 2017-01-05 46 166 = 46 + 55 + 23 + 42
jack 2017-01-08 55 120 = 55 + 23 + 42
jack 2017-02-03 23 65 = 23 + 42
jack 2017-04-06 42 42 = 42
mart 2017-04-08 62 299
mart 2017-04-09 68 237
mart 2017-04-11 75 169
mart 2017-04-13 94 94
neil 2017-05-10 12 92
neil 2017-06-12 80 80
tony 2017-01-02 15 94
tony 2017-01-04 29 79
tony 2017-01-07 50 50
2.4 Rank
函數說明
rank():排序相同時會重複,總數不會變
dense_rank():排序相同時會重複,總數會減少
row_number():會根據順序計算
select name,subject,score,
rank() over(partition by subject order by score desc) rp,
dense_rank() over(partition by subject order by score desc) drp,
row_number() over(partition by subject order by score desc) rmp
from score;
結果 :
name subject score rp drp rmp
孫悟空 數學 95 1 1 1
宋宋 數學 86 2 2 2
婷婷 數學 85 3 3 3
大海 數學 56 4 4 4
宋宋 英語 84 1 1 1
大海 英語 84 1 1 2
婷婷 英語 78 3(跳過2)2 3
孫悟空 英語 68 4 3(總數少) 4
大海 語文 94 1 1 1
孫悟空 語文 87 2 2 2
婷婷 語文 65 3 3 3
宋宋 語文 64 4 4 4
2.5 行轉列
- CONCAT(string A, string B):
返回輸入字符串
連接後
的結果,支持任意個輸入字符串;
CONCAT_WS(separator, str1, str2,…):
特殊形式的 CONCAT()。第一個參數剩餘參數間的分隔符。分隔符可以是與剩餘參數一樣的字符串。如果分隔符是 NULL,返回值也將爲 NULL。COLLECT_SET(col):
只接受基本數據類型,主要作用是將某字段的值進行去重彙總,產生 array 類型字段。多行彙總成一個 array 類型。
2.6 列轉行
- EXPLODE(col):
將 hive 一列中複雜的 array 或者 map 結構拆分成多行。
- LATERAL VIEW
用法:LATERAL VIEW udtf(expression) table Alias AS columnAlias
解釋:用於和 split, explode 等 UDTF 一起使用,它能夠將一列數據拆成多行數據,在此基礎上可以對拆分後的數據進行聚合。
3 Hive 調優
3.1 MapJoin
如果不指定 MapJoin 或者不符合 MapJoin 的條件,那麼 Hive 解析器會將 Join 操作轉換成 Common Join,也就是在 Reduce 階段完成 join。容易發生數據傾斜。可以用 MapJoin 把小表全部加載到內存在 map 端進行 join,避免 reducer 處理。
3.2 行列過濾
列處理:在 SELECT 時只拿需要的列,儘量使用分區過濾,少用 SELECT *。
行處理:在分區剪裁中,當使用外關聯時,如果將副表的過濾條件寫在 Where 後面,那麼就會先全表關聯,之後再過濾。
3.3 合理設置 Map 數跟 Reduce 數
3.3.1 map 數不是越多越好
如果一個任務有很多小文件(遠遠小於塊大小 128m),則每個小文件也會被當做一個塊,用一個 map 任務來完成,而一個 map 任務啓動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費 。而且,同時可執行的 map 數是受限的。此時我們就應該減少 map 數量。
3.3.2 Reduce 數不是越多越好
-
過多的啓動和初始化 Reduce 也會消耗時間和資源;
-
有多少個 Reduce,就會有多少個輸出文件,如果生成了很多個小文件,那麼如果這些小文件作爲下一個任務的輸入,則也會出現小文件過多的問題;
-
Reduce 個數設置考慮這兩個原則:處理大數據量利用合適的 Reduce 數;使單個 Reduce 任務處理數據量大小要合適;
3.4 嚴格模式
嚴格模式 strict 下會有以下特點:
-
對於分區表,用戶不允許掃描所有分區。
-
使用了 order by 語句的查詢,要求必須使用 limit 語句。
-
限制笛卡爾積的查詢。
3.5 開啓 map 端 combiner
在不影響最終業務邏輯前提下,手動開啓 set hive.map.aggr=true;
3.6 壓縮
設置 map 端輸出中間結果壓縮,加速網絡傳輸。
3.7 小文件進行合併
在 Map 執行前合併小文件,減少 Map 數,CombineHiveInputFormat 具有對小文件進行合併的功能(系統默認的格式)。HiveInputFormat 沒有對小文件合併功能。
3.8 其他
-
Fetch 抓取:指的是 Hive 中對某些情況的查詢可以不必使用 MapReduce 計算。
-
本地模式:Hive 可以通過本地模式在單臺機器上處理所有的任務。
-
數據分區:數據細化存儲方便訪問。
-
JVM 重用:JVM 實例在同一個 job 中重新使用 N 次。
-
推測執行:根據一定的法則推測出拖後腿的任務,併爲這樣的任務啓動一個備份任務。
-
並行執行:一個 Hive 查詢被分解成多個階段,階段之間並非完全互相依賴的。
4 Hive 高頻考點
4.1 數據傾斜
4.1.1 定義
數據分佈不平衡,某些地方特別多,某些地方又特別少,導致的在處理數據的時候,有些很快就處理完了,而有些又遲遲未能處理完,導致整體任務最終遲遲無法完成,這種現象就是數據傾斜。
4.1.2 產生
-
key 的分佈不均勻或者說某些 key 太集中
-
業務數據自身的特性,例如不同數據類型關聯產生數據傾斜
-
SQL 語句導致的數據傾斜
4.1.3 解決
-
不影響最終業務邏輯前提下開啓 map 端 combiner。
-
開啓數據傾斜時負載均衡。
-
手動抽查做好分區規則。
-
使用 mapjoin,小表進內存 在 Map 端完成 Reduce。
4.2 分區表和分桶表對比?
4.2.1 分區表
-
分區使用的是
表外
字段,需要指定字段類型 -
分區通過
關鍵字
partitioned by(partition_name string) 聲明 -
分區劃分粒度
較粗
-
將數據按區域劃分開,查詢時不用掃描無關的數據,加快查詢速度
4.2.2 分桶表
分桶邏輯:對分桶字段求哈希值,用哈希值與分桶的數量取餘決定數據放到哪個桶裏。
-
分桶使用的是
表內
字段,已經知道字段類型,不需要再指定。 -
分桶表通過關鍵字 clustered by(column_name) into … buckets 聲明
-
分桶是
更細
粒度的劃分、管理數據,可以對錶進行先分區再分桶的劃分策略 -
優點在於用於數據取樣時候能夠起到優化加速的作用
4.3 動態分區
-
靜態分區與動態分區的主要區別在於靜態分區是手動指定,而動態分區是通過數據來進行判斷。
-
靜態分區的列是在編譯時期,通過用戶傳遞來決定的,動態分區只有在 SQL 執行時才能決定。
-
系統默認開啓,非嚴格模式,動態分區最大值。
4.4 Hive 中視圖跟索引
4.4.1 視圖
視圖是一種使用查詢語句定義的虛擬表,是數據的一種邏輯結構,創建視圖時不會把視圖存儲到磁盤上,定義視圖的查詢語句只有在執行視圖的語句時纔會被執行。視圖是隻讀的,不能向視圖中插入或是加載數據
4.4.2 Hive 索引
Hive 支持在表中建立索引。但是索引需要額外的存儲空間,因此在創建索引時需要考慮索引的必要性。
Hive 不支持直接使用 DROP TABLE 語句刪除索引表。如果創建索引的表被刪除了,則其對應的索引和索引表也會被刪除;如果表的某個分區被刪除了,則該分區對應的分區索引也會被刪除。
4.5 Sort By、Order By、Distrbute By、Cluster By
-
Sort By:分區內有序
-
Order By:全局排序,只有一個 Reducer
-
Distrbute By:類似 MR 中 Partition,進行分區,結合 sort by 使用
-
Cluster By:當 Distribute by 和 Sorts by 字段相同時,可以使用 Cluster by 方式。Cluster by 還兼具 Sort by 的功能,但只能是升序排序。
4.6 內部表 跟外部表
4.6.1 內部表
如果 Hive 中沒有特別指定,則默認創建的表都是管理表,也稱內部表。由 Hive 負責管理表中的數據,管理表不共享數據。刪除管理表時,會刪除管理表中的數據和元數據信息。
4.6.2 外部表
當一份數據需要被共享時,可以創建一個外部表指向這份數據。刪除該表並不會刪除掉原始數據,刪除的是表的元數據。
4.7 UDF 、UDAF、UDTF
-
UDF :一進一出,類似 upper,trim
-
UDAF:多進一出,聚集函數,類似 count、max、min。
-
UDTF:一進多出,如 lateral view explore()
4.8 HQL 如何轉變爲 MapReduce
-
Antlr 定義 SQL 語法規則,完成 SQL 詞法,語法解析,SQL 轉化爲 抽象語法樹 AST Tree。
-
遍歷 AST Tree,抽象出查詢的基本組成單元 QueryBlock。
-
遍歷 QueryBlock,翻譯爲執行操作樹 OperatorTree。
-
邏輯層優化 OperatorTree 變換,合併不必要的 ReduceSinkOperator,減少 Shuffle 數量。
-
遍歷 OperatorTree 翻譯爲 MapReduce 任務。
-
物理層優化器進行 MapReduce 任務變換,生成最終執行計劃。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Js7MRNs94EgryqDuJqtEtA