#### 先說一些廢話 總結一下Hive面試寶典,方便讀者快速過一遍Hive面試所需要的知識點 ## Hive的介紹 ### Hive和Hadoop的關係 1. Hive利用hdfs存儲數據,利用MapReduce查詢數據 2. Hive的數據存儲在hdfs上,簡單的說Hive就是hdfs的簡單一種 ...
先說一些廢話
總結一下Hive面試寶典,方便讀者快速過一遍Hive面試所需要的知識點
Hive的介紹
Hive和Hadoop的關係
- Hive利用hdfs存儲數據,利用MapReduce查詢數據
- Hive的數據存儲在hdfs上,簡單的說Hive就是hdfs的簡單一種映射,比如:Hive的一張表映射hdfs上的一個文件,Hive的一個資料庫就映射為hdfs上的文件夾
- Hive是一個計算框架,他是MapReduce的一種封裝,實際上他的底層還是MR,Hive就是用人們熟悉的sql對數據進行分析的
- Hive執行程式是運行在Yarn上的
Hive的特點
- Hive可以自由的擴展集群的規模,一般情況下不需要重啟服務(世界上最大的Hadoop集群在Yahoo!,2009年的規模在4000台節點左右)
- Hive支持用戶自定義函數,用戶可以根據自己的需求來實現自己的函數(可能會引申自定義函數)
- 良好的容錯性,節點出現問題SQL仍可完成執行(可能會拓展數據傾斜相關問題,或者直接問你你工作中有沒有遇到這樣的問題)
Hive的缺點
- Hive的HQL表達能力有限。迭代式演算法無法表達;數據挖掘方面不擅長
- Hive的效率比較低。Hive自動生成的MapReduce作業,通常情況下不夠智能化;Hive調優比較困難,粒度較粗
- Hive執行延遲
- Hive 在查詢數據的時候,由於沒有索引,需要掃描整個表,因此延遲較高
- 另外一個導致 Hive 執行延遲高的因素是 MapReduce框架,由於MapReduce 本身具有較高的延遲,因此在利用MapReduce 執行Hive查詢時,也會有較高的延遲
- 相對的,資料庫的執行延遲較低。當然,這個低是有條件的,即數據規模較小,當數據規模大到超過資料庫的處理能力的時候,Hive的並行計算顯然能體現出優勢
Hive常見的應用場景
- 日誌分析:大部分互聯網公司使用Hive進行日誌分析,包括百度、淘寶等
- 統計網站一個時間段內的pv、uv
- 多維度數據分析
- 海量結構化數據離線分析
Hive和mysql的區別
- Hive採用了類SQL的查詢語言HQL(hive query language),除了HQL之外,其餘無任何相似的地方,Hive是為了數據倉庫設計的
- 存儲位置:Hive在Hadoop上;mysql將數據存儲在設備或本地系統中
- 數據更新:Hive不支持數據的改寫和添加,是在載入的時候就已經確定好了;資料庫可以CRUD
- 索引:Hive無索引,每次掃描所有數據,底層是MR,並行計算,適用於大數據量;mysql有索引,適合線上查詢數據
- 執行:Hive底層是MarReduce;mysql底層是執行引擎
- 可擴展性:Hive:大數據量,慢慢擴去吧;mysql:相對就很少了
Hive的架構
# Hive架構簡易示意
Meta Store ->
Client (CLI/JDBC/WebGUI +
Driver/驅動 +
SQL Parser/解析器 +
Physical Plan/編譯器 +
QueryOptimizer/優化器 +
Execution/執行器) ->
MapReduce ->
HDFS
- 用戶介面:Hive 對外提供了三種服務模式,即 Hive 命令行模式(CLI),Hive 的 Web 模式(WUI),Hive 的遠程服務(Client)
- 其中最常用的是 CLI shell 命令行,CLI 啟動的時候,會同時啟動一個Hive副本
- WUI 是通過瀏覽器訪問 Hive,預設埠是9999
- Client 是Hive的客戶端,,在啟動 Client模式 的時候,需要指出 Hive Server 所在節點,並且在該節點啟動 Hive Server
- JDBC/ODBC用 JAVA 實現,與傳統資料庫 JDBC 類似
- 元數據存儲:通常是存儲在關係資料庫如 mysql , derby中
- Hive中的元數據包括表的名字,表的列和分區及其屬性,表的屬性(是否為外部表等),表的數據所在目錄等
- 解釋器、編譯器、優化器、執行器
- 解釋器、編譯器、優化器完成 HQL 查詢語句從詞法分析、語法分析、編譯、優化以及查詢計劃的生成
- 生成的查詢計劃存儲在 HDFS 中,併在隨後有 MapReduce 調用執行(註意!!!包含*的查詢,比如select * from tbl不會生成MapRedcue任務)
- ===============================================================
- 解析器(parser):將查詢字元串轉化為解析樹表達式
- ===============================================================
- 編譯器(physical plan):分為
語義分析器(semantic analyzer)
和邏輯策略生成器(logical plan generator)
- 語義分析器(semantic analyzer):將解析樹表達式轉換為基於塊(block-based)的內部查詢表達式
- 邏輯策略生成器(logical plan generator):將內部查詢表達式轉換為邏輯策略,這些策略由邏輯操作樹組成
- ===============================================================
- 優化器(optimizer):通過邏輯策略構造多途徑並以不同方式重寫
Hive的數據
Hive的數據模型
- Hive中所有的數據都存儲在hdfs中,沒有專門的數據存儲格式(可支持TextFile,SequenceFile,ParquetFile,RCFILE等)
- 只需要在創建表的時候告訴Hive數據中的列分隔符和行分隔符,Hive就可以解析數據
- Hive中包含以下數據模型:DB、Table、External Table、Partition、Bucket
- DB:在hdfs中表現為
${hive.metastore.warehouse.dir}
目錄下一個文件夾 - Table:在hdfs中表現所屬db目錄下一個文件夾,普通表刪除表後,hdfs上的文件都刪了
- External Table:外部表, 與table類似,不過其數據存放位置可以在任意指定路徑,外部表刪除後,hdfs上的文件沒有刪除,只是把文件刪除了
- Partition:在hdfs中表現為table目錄下的子目錄
- Bucket:桶在hdfs中表現為同一個表目錄下根據hash散列之後的多個文件,會根據不同的文件把數據放到不同的文件中
- DB:在hdfs中表現為
Hive的底層如何存儲Null值
- Null在Hive底層預設是用'\N'來存儲的
- 能夠經過
alter table test SET SERDEPROPERTIES('serialization.null.format' = 'a');
來修改
Hive中元數據metadata
和元數據商店metastore
的作用
- metadata即元數據,元數據包含用Hive創建的database、tabel等的元信息,元數據存儲在
關係型資料庫(RDBMS)
中,如derby、mysql等 - metastore的作用是:客戶端連接metastore服務,metastore再去連接mysql資料庫來存取元數據,
有了metastore服務,就可以有多個客戶端同時連接,而且這些客戶端不需要知道mysql資料庫的用戶名和密碼,只需要連接metastore服務即可
Hive有哪些保存元數據metadata
的方式
- 內嵌模式:將元數據保存在本地內嵌的derby資料庫中,內嵌的derby資料庫每次只能訪問一個數據文件,也就意味著它不支持多會話連接,適用於用來實驗,不適用於生產環境
- 本地模式:將元數據保存在本地獨立的資料庫中(一般是mysql),這可以支持多會話連接
- 遠程模式:把元數據保存在遠程獨立的mysql資料庫中,避免每個客戶端都去安裝mysql資料庫
- 需要註意的是: 記憶體資料庫derby,安裝小,但是數據存在記憶體,不穩定。mysql資料庫,數據存儲模式可以自己設置,持久化好,查看方便
Hive元數據存儲方式中,本地模式和遠程模式的區別
- 本地元存儲和遠程元存儲都採用外部資料庫來存儲元數據
- 本地元存儲不需要單獨起metastore服務,用的是跟Hive在同一個進程里的metastore服務
- 遠程元存儲需要單獨起metastore服務,然後每個客戶端都在配置文件里配置連接到該metastore服務,遠程元存儲的metastore服務和Hive運行在不同的進程
Hive的數據類型
- 基本數據類型,因為Hive的底層是用java開發,所以基本數據類型和java保持一致
- 整型 tinyint(位元組整型) / smallint(短整型) / int(整型) / bigint(長整型),分別占用1/2/4/8個位元組,等價於java的 byte/short/int/long
- 浮點型 float(浮點型) / double(雙精度浮點型),分別占用4/8個位元組,等價於java的 float/double
- 字元型 string,等價於資料庫的 varchar,可變字元串,理論上可以存儲2GB的位元組
- 布爾型 boolean,等價於java的 boolean
- 複雜數據類型
- array/map,等價於java的array/map
- struct,等價於c語言中的struct
- 類型轉換
- Hive 的原子數據類型是可以進行隱式轉換的,類似於 Java 的類型轉換
- 例如某表達式使用 int 類型,tinyint 會自動轉換為 int 類型
- 但是 Hive 不會進行反向轉化,例如,某表達式使用 tinyint 類型,int 不會自動轉換為 tinyint 類型,它會返回錯誤,除非使用 CAST 操作
- ===============================================================
- 可以使用 CAST 操作顯示進行數據類型轉換
- 例如 CAST('1' AS INT) 將把字元串'1' 轉換成整數 1
- 如果強制類型轉換失敗,如執行 CAST('X' AS INT),表達式返回空值 NULL
Hive的隱式類型轉換規則
- 任何整數類型都可以隱式地轉換為一個範圍更廣的類型,如 tinyint 可以轉換成 int,int 可以轉換成 bigint
- 所有整數類型、float 和 string 類型都可以隱式地轉換成 double
- tinyint、smallint、int 都可以轉換為 float
- boolean 類型不可以轉換為任何其它的類型
Hive數據存儲所使用的文件格式
- 預設是TextFile文件格式
- 文本格式,Hive的預設格式,數據不壓縮,磁碟開銷大、數據解析開銷大
- 對應的Hive API為:
org.apache.hadoop.mapred.TextInputFormat和org.apache.hive.ql.io.HiveIgnoreKeyTextOutputFormat;
- 可結合Gzip、Bzip2使用(系統自動檢查,執行查詢時自動解壓),但是使用這種方式,hive不會對數據進行切分,從而無法對數據進行並行操作
- RCFile文件格式
- RCFile是一種行列存儲相結合的存儲方式,先將數據按行進行分塊再按列式存儲,保證同一條記錄在一個塊上,避免讀取多個塊,有利於數據壓縮和快速進行列存儲
- 對應Hive API為:
org.apache.hadoop.hive.ql.io.RCFileInputFormat和org.apache.hadoop.hive.ql.io.RCFileOutputFormat;
- ORCFile文件格式
- 數據按行分塊,每塊按照列存儲,不是真正意義上的列存儲,可以理解為分段列存儲
- 用於降低Hadoop數據存儲空間和加速Hive查詢速度
- ORCfile特點是壓縮比比較高,壓縮快,快速列存取,是RCfile的改良版本,相比RCfile能夠更好的壓縮,更快的查詢
- 需要註意的是ORC在讀寫時候需要消耗額外的CPU資源來壓縮和解壓縮,當然這部分的CPU消耗是非常少的
- 優點:
每個task只輸出單個文件,減少namenode負載; 支持各種複雜的數據類型,比如:datetime,decima以及複雜類型struct、list、map; 文件中存儲了一些輕量級的索引數據; 基於數據類型的塊模式壓縮:integer類型的列用行程長度編碼,string類型的列使用字典編碼; 用多個相互獨立的recordReaders並行讀相同的文件 無需掃描markers即可分割文件 綁定讀寫所需記憶體 metadata存儲用protocol buffers,支持添加和刪除列
- SequenceFile文件格式
- Hadoop提供的二進位文件,Hadoop支持的標準文件
- 數據直接序列化到文件中,SequenceFile文件不能直接查看,可以通過Hadoop fs -text查看
- SequenceFile具有使用方便、可分割、可壓縮、可進行切片,壓縮支持NONE、RECORD、BLOCK(優先)
- 對應Hive API:
org.apache.hadoop.mapred.SequenceFileInputFormat和org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat;
- Parquet文件格式
- 二進位存儲,面向分析性的存儲格式
- 能夠很好的壓縮,同時減少大量的表掃描和反序列化的時間,有很好的查詢性能,支持有限的模式演進,但是寫速度通常比較慢
- Parquet文件是以二進位方式存儲的,所以是不可以直接讀取的,文件中包括該文件的數據和元數據,因此Parquet格式文件是自解析的
- 總結
- TextFile 存儲空間消耗比較大,並且壓縮的text無法分割和合併查詢的效率最低,可以直接存儲,載入數據的速度最高
- SequenceFile 存儲空間消耗最大,壓縮的文件可以分割和合併,查詢效率高
- ORCFile / RCFile 存儲空間最小,查詢的效率最高,載入的速度最低
- Parquet 格式是列式存儲,有很好的壓縮性能和表掃描功能
- SequenceFile / ORCFile / RCFile 格式的表不能直接從本地文件導入數據,數據要先導入到TextFile格式的表中,
然後再從TextFile表中導入到SequenceFile/ORCFile/RCFile表中
Hive中使用的壓縮演算法
- 我們原始數據使用的是LZO的壓縮格式,因為原始數據比較大,所以選擇了支持切割的LZO壓縮
- 清洗過的數據存到DWD層,我們在DWS中需要對清洗後的數據進行分析,所以我們DWD層使用的存儲格式是Parquet,壓縮格式是Snappy
- 之前我們壓縮還遇到過一個問題,當時之前的項目中使用的是Snappy+ORC存儲,後來我發現使用Snappy+ORC 存儲比ORC單獨存儲還多占用了近一半的空間
- 後來我又對各個壓縮格式及存儲格式的結合做了一個測試,最終單獨使用ORC存儲節省了大量的空間
- Snappy壓縮格式
- 其中壓縮比bzip2 > zlib > gzip > deflate > snappy > lzo > lz4,在不同的測試場景中,會有差異,這僅僅是一個大概的排名情況
- bzip2、zlib、gzip、deflate可以保證最小的壓縮,但在運算中過於消耗時間
- 從壓縮性能上來看:lz4 > lzo > snappy > deflate > gzip > bzip2,其中lz4、lzo、snappy壓縮和解壓縮速度快,壓縮比低
- 所以一般在生產環境中,經常會採用lz4、lzo、snappy壓縮,以保證運算效率
什麼是數據可分割
-
在考慮如何壓縮那些將由MapReduce處理的數據時,考慮壓縮格式是否支持分割是很重要的。
考慮存儲在HDFS中的未壓縮的文件,其大小為1GB,HDFS的塊大小為64MB,所以該文件將被存儲為16塊。
將此文件用作輸入的MapReduce作業會創建1個輸人分片(split,也稱為“分塊”。對於block,我們統一稱為“塊”。)
每個分片都被作為一個獨立map任務的輸入單獨進行處理 -
現在假設,該文件是一個gzip格式的壓縮文件,壓縮後的大小為1GB。和前面一樣,HDFS將此文件存儲為16塊。
然而,針對每一塊創建一個分塊是沒有用的,因為不可能從gzip數據流中的任意點開始讀取,map任務也不可能獨立於其他分塊只讀取一個分塊中的數據。
gzip格式使用DEFLATE來存儲壓縮過的數據,DEFLATE將數據作為一系列壓縮過的塊進行存儲。
問題是,每塊的開始沒有指定用戶在數據流中任意點定位到下一個塊的起始位置,而是其自身與數據流同步。
因此,gzip不支持分割(塊)機制。 -
在這種情況下,MapReduce不分割gzip格式的文件,因為它知道輸入是gzip壓縮格式的(通過文件擴展名得知),而gzip壓縮機制不支持分割機制。
因此一個map任務將處理16個HDFS塊,且大都不是map的本地數據。
與此同時,因為map任務少,所以作業分割的粒度不夠細,從而導致運行時間變長。
關於壓縮模式說明
- 壓縮模式評價:
可使用以下三種標準對壓縮方式進行評價: 壓縮比:壓縮比越高,壓縮後文件越小,所以壓縮比越高越好。 壓縮時間:越快越好。 已經壓縮的格式文件是否可以再分割:可以分割的格式允許單一文件由多個Mapper程式處理,可以更好的並行化。
- 壓縮模式對比
BZip2有最高的壓縮比但也會帶來更高的CPU開銷,Gzip較BZip2次之。 如果基於磁碟利用率和I/O考慮,這兩個壓縮演算法都是比較有吸引力的演算法。 LZO和Snappy演算法有更快的解壓縮速度,如果更關註壓縮、解壓速度,它們都是不錯的選擇。 LZO和Snappy在壓縮數據上的速度大致相當,但Snappy演算法在解壓速度上要較LZO更快。 Hadoop的會將大文件分割成HDFS block(預設64MB)大小的splits分片,每個分片對應一個Mapper程式。 在這幾個壓縮演算法中 BZip2、LZO、Snappy壓縮是可分割的,Gzip則不支持分割。
Hive的安裝與使用
當前版本請閱讀以下參考資料,後期再行完善
- hive的安裝和使用
- Hive入門及常用指令
- 更多進階內容請自行百度拓展查閱
如何在Hive中集成HBase
- 將Hbase的客戶端
jar
拷貝至Hive/lib
目錄下 - 修改
hive/conf
下的hive-site.xml
配置文件,添加如下屬性:<poperty> <name>hbase.zookeeper.quorum</name> <value>hadoop</value> </poperty>
- 啟動Hive,創建表管理表
hbase_table_1
,指定數據存儲在Hbase表中,主要是通過stored by HBaseStorageHandler
類來實現 - 往Hive表
hbase_table_1
表中插入數據
如何通過 HiveSQL 來直接讀寫 HBase
當前版本請閱讀以下參考資料,後期再行完善
- 如何整合hive和hbase
- HiveHbase集成實踐
- 更多進階內容請自行百度拓展查閱
Hive的分區和分桶
Hive的分區分桶都是數據存儲和組織的策略,分區類似文件的分類歸檔,分桶類似於傳統資料庫的索引
什麼是Hive分區
- Hive中資料庫,表,及分區都是在HDFS存儲的一個抽象
- Hive中的一個分區對應的就是HDFS的一個目錄,目錄名就是分區欄位
- 聲明分區表
PARTITIONED BY (name string)
,分區鍵不能和任何列重名 - 聲明數據要導入的分區
PARTITION(name="fx67ll")
- 查看分區
SHOW PARTITIONAS
- 根據分區查詢
WHERE name = "fx67ll"
- 指定切分格式
ROW FORMAT DELIMITED # 每個欄位之間由[ , ]分割 FIELDS TERMINATED BY ',' # 欄位是Array形式,元素與元素之間由[ - ]分割 COLLECTION ITEMS TERMINATED BY '-' # 欄位是K-V形式,每組K-V對內部由[ : ]分割 MAP KEYS TERMINATED BY ':';
Hive分區的優點
- 如果一個表中有大量的數據,我們全部拿出來做查詞的功能,耗時比較長,查詢較慢,
使用了分區,就可以做到用到了那個分區就拿那個分區中的數據方便了查詢,提高了查詞的效率 - 橫向分配數據,使得負載更為均衡
Hive分區的缺點
- 容易造成過多的小分區,過多的目錄
- 如果分區策略不佳,容易導致分區數據不均衡,造成數據傾斜
什麼是Hive分桶
- 分桶是相對分區進行更細粒度的劃分,分桶將整個數據內容按照某列屬性值得hash值進行區分,類似於關係型數據的索引
- 如要安裝id屬性分為3個桶,就是對id屬性值的hash值對3取摸,按照取模結果對數據分桶,
如取模結果為0的數據記錄存放到一個文件,取模為1的數據存放到一個文件,取模為2的數據存放到一個文件 - 分桶之前要執行命令
set hive.enforce.bucketing = true
- 聲明分桶表
CLUSTERED BY(id) INTO 3 BUCKETS
關於Hive索引的說明
- 即從3.0開始索引已經被移除,有一些可替代的方案可能與索引類似:
- 具有自動重寫的物化視圖可以產生非常相似的結果,Hive2.3.0增加了對物化視圖視圖的支持
- 使用列式文件格式((Parquet、ORC)–他們可以進行選擇性掃描;甚至可以跳過整個文件/塊。很顯然,例如我們創建表時使用的ORC格式就已經具有了索引的功能
- Hive為什麼刪除了索引:
- 由於Hive是針對海量數據存儲的,創建索引需要占用大量的空間,最主要的是Hive索引無法自動進行刷新,也就是當新的數據加入時候,無法為這些數據自動加入索引
Hive分桶的優點
- 分桶欄位需要根據業務進行設定,可以解決數據傾斜問題,主要是在關聯join的時候通過map端更快的連接
- 能夠提供類似的哈希的快速響應,比分區更快
Hive分桶的缺點
- 需要在建表時規劃好分桶策略,需要手動載入數據到分桶表
- 本質是空間換時間,時間換效率,所以在載入數據到表的時候有空間和時間上的消耗
Hive中靜態分區和動態分區的區別
- 靜態分區與動態分區的主要區別在於靜態分區是手動指定,而動態分區是通過數據來進行判斷
- 詳細來說,靜態分區的列實在編譯時期,通過用戶傳遞來決定的;動態分區只有在SQL執行時才能決定
- 查詢和寫入的時候,靜態分區鍵要用
<static partition key> = <value>
指定分區值;動態分區只需要給出分出分區鍵名稱<dynamic partition key>
- 一張表可同時被靜態和動態分區鍵分區,只是動態分區鍵需要放在靜態分區建的後面,因為HDFS上的動態分區目錄下不能包含靜態分區的子目錄
Hive動態分區的參數設定
- 開啟動態分區
# 開啟動態分區功能,預設false set hive.exec.dynamic.partition = true # 允許所有分區都是動態的,否則必須有靜態分區欄位,預設strict set hive.exec.dynamic.partition.mode = nonstrict
- 動態分區參數調優
# 每個mapper或reducer可以允許創建的最大動態分區個數,預設是100,超出則會報錯 set hive.exec.max.dynamic.partitions.pernode = 1000 # 一個動態分區語句可以創建的最大動態分區個數,預設是1000,超出報錯 set hive.exec.max.dynamic.partitions = 10000 # 全局可以創建的最大文件個數,預設是10000,超出報錯 set hive.exec.max.created.files =100000
Hive的內部表和外部表
什麼是Hive的內部表和外部表
- 沒有
external
修飾,表數據保存在Hive預設的路徑下,數據完全由Hive管理,刪除表時元數據(metadata)和表數據都會一起刪除 - 有
external
修飾,表數據保存在HDFS上,該位置由用戶指定,刪除表時,只會刪除表的元數據(metadata)
Hive內部表和外部表的區別是什麼
- 內部表數據由Hive自身管理,外部表數據由HDFS管理
- 內部表數據存儲的位置是
hive.metastore.warehouse.dir
,預設是/user/hive/warehouse
- 外部表數據的存儲位置由自己制定,如果沒有LOCATION,Hive將在HDFS上的
/user/hive/warehouse
文件夾下以外部表的表名創建一個文件夾,並將屬於這個表的數據存放在這裡 - 刪除內部表會直接刪除元數據(metadata)及存儲數據
- 刪除外部表僅僅會刪除元數據(metadata),HDFS上的文件並不會被刪除
- 對內部表的修改會將修改直接同步給元數據(metadata),而對外部表的表結構和分區進行修改,則需要修複
MSCK REPAIR TABLE table_name
生產環境中為什麼建議使用外部表
- 因為外部表不會載入數據到Hive,減少數據傳輸,數據還能共用
- Hive不會修改數據,所以無需擔心數據的損壞
- 刪除表時,只刪除表結構,不刪除數據
Hive SQL
Hive中的SQL如何轉化成MapReduce任務的
Antlr
定義SQL的語法規則,完成SQL詞法,語法解析,將SQL轉化為抽象語法樹- 遍歷抽象語法樹抽象出查詢的基本組成單元
QueryBlock
- 遍歷
QueryBlock
,翻譯為執行操作樹OperatorTree
- 邏輯層優化器進行
OperatorTree
變換,合併不必要的ReduceSinkOperator
,減少shuffle
數據量 - 遍厲
OperatorTree
,翻譯為MapReduce
任務 - 物理層優化器進行
MapReduce
任務的變換,生成最終的執行計劃
什麼情況下Hive不走MapReduce任務
Hive中如何查詢A表中B表不存在的數據
題目:A、B兩表,找出ID欄位中,存在A表,但是不存在B表的數據。A表總共13w數據,去重後大約3W條數據,B表有2W條數據,且B表的ID欄位有索引
select * from B
where (select count(1) as num from A where A.ID = B.ID) = 0
Hive中有哪些連接查詢以及如何使用
當前版本請閱讀以下參考資料,後期再行完善
- Hive——join的使用
- 更多進階內容請自行百度拓展查閱
Hive中左連接和內連接的區別
- 內連接:連接的鍵匹配上就連接,沒有匹配上就過濾掉
- 左連接:以左表為基準,與右表做關聯,關聯上則連接,右表關聯不上的則為null
Hive中左連接的底層原理
參考下麵Hive查詢的時候on和where有什麼區別的理解二
Hive查詢的時候 ON 和 WHERE 有什麼區別
共同點
- on先執行,where後執行
- 並且where是對連接之後的結果進行的查詢條件
第一種理解方式
- 條件不為主表條件的時候,放在on和where的後面一樣
- 條件為主表條件的時候,放在on後面,結果為主表全量,放在where後面的時候為主表條件篩選過後的全量
1. select * from a left join b on a.id = b.id and a.dt=20181115;
2. select * from a left join b on a.id = b.id and b.dt=20181115;
3. select * from a join b on a.id = b.id and a.dt=20181115;
4. select * from a left join b on a.id = b.id where a.dt=20181115;
sql1: 如果是left join 在on上寫主表a的條件不會生效,全表掃描。
sql2: 如果是left join 在on上寫副表b的條件會生效,但是語義與寫到where 條件不同
sql3: 如果是inner join 在on上寫主表a、副表b的條件都會生效
sql4: 建議這麼寫,大家寫sql大部分的語義都是先過濾數據然後再join,所以在不瞭解join on+條件的情況下,條件儘量別寫在on後,
直接寫到where後就ok了,如果where條件後寫b表的過濾條件,就變成了先left join出結果再按照b條件過濾數據
第二種理解方式
on
是在生成連接表的起作用的,where
是生成連接表之後對連接表再進行過濾- 當使用
left join
時,無論on
的條件是否滿足,都會返回左表的所有記錄,對於滿足的條件的記錄,兩個表對應的記錄會連接起來,對於不滿足條件的記錄,那右表欄位全部是null - 當使用
right join
時,類似,只不過是全部返回右表的所有記錄 - 當使用
inner join
時,功能與where
完全相同
經過親測後,更加深了對on和where的理解,得出以下結論:
1.ON後的條件如果有過濾主表的條件,則結果對於不符合該條件的主表數據也會原條數保留,只是不匹配右表數據而已。對於on後面對右表的過濾條件,連接時會用該條件直接過濾右表數據後再和左邊進行左連接。總之,對於不滿足on後面的所有條件的數據,左表會在結果數據中原條數保留數據,只是不匹配右表數據而已。不滿足條件的右表數據各欄位會直接以NULL連接主表。
2.ON後對左表的篩選條件對於結果行數會被忽略,但會影響結果中的匹配右表數據,因為只有符合左表條件的數據才會去和符合條件的右表數據進行匹配,不符合條件的左表數據會保留在最後結果中,但匹配的右表數據都是NULL.因此,對於需要過濾左表數據的話,需要把過濾條件放到where後面。
3.ON後的左表條件(單獨對左表進行的篩選條件)對於結果行數無影響,還是會返回所有左表的數據,但和右表匹配數據時,系統只會拿左表符合條件(ON後的對左表過濾條件)的數據去和右表符合條件(ON後的對右表過濾條件)的數據進行匹配抓取數據,而不符合條件的左表數據還是會出現在結果列表中,只是對應的右表數據都是NULL。
4.ON後的右表條件(單獨對右表進行的篩選條件)會先對右表進行數據篩選後再和左表做連接查詢,對結果行數有影響(當左表對右表是一對多時),但不會影響左表的顯示行數,然後拿符合條件的右表數據去和符合條件的左表數據進行匹配。
5.Where還是對連接後的數據進行過濾篩選,這個無異議。
6.匹配數據時無論左右表,都是拿符合ON後的過濾條件去做數據匹配,不符合的會保留左表數據,用NULL填充右表數據。
綜上得出,ON後面對於左表的過濾條件,在最後結果行數中會被忽略,並不會先去過濾左表數據再連接查詢,但是ON後的右表條件會先過濾右表數據再連接左表進行查詢。
連接查詢時,都是用符合ON後的左右表的過濾條件的數據進行連接查詢,只有符合左右表過濾條件的數據才能正確匹配,剩下的左表數據會正常出現在結果集中,但匹配的右表數據是NULL。因此對於左表的過濾條件切記要放到Where後,對於右表的過濾條件要看情況了。如果需要先過濾右表數據就把條件放到ON後面即可。
Hive 函數
關於 UDF/UDAF/UDTF 的提問
- 如何使用UDF/UDAF/UDTF
- 為什麼使用UDF/UDAF/UDTF
- 你寫過什麼樣的UDF/UDAF/UDTF
- Hive自定義函數實現了什麼函數
上述四個問題自行 參考資料 並結合工作中實際場景來作答,沒有標準答案
Hive中如何去重
第一種方式:使用 DISTINCT
- 對select 後面所有欄位去重,並不能只對一列去重
- 當
DISTINCT
應用到多個欄位的時候,DISTINCT
必須放在開頭,其應用的範圍是其後面的所有欄位,而不只是緊挨著它的一個欄位,而且DISTINCT
只能放到所有欄位的前面 DISTINCT
對NULL
是不進行過濾的,即返回的結果中是包含NULL
值的- 聚合函數中的
DISTINCT
,如count()
會過濾掉為NULL
第二種方式:使用 GROUP BY
- 對
GROUP BY
後面所有欄位去重,並不能只對一列去重
第三種方式:使用 ROW_NUMBER() OVER
視窗函數
- 參考資料一:一種巧妙的hive sql數據去重方法
- 參考資料二:Hive--數據去重及row_number()
- 參考資料三:Hive(十一)--數據去重及row_number()
Hive中排序函數的使用方式及區別
order by
會對輸入做全局排序,為保證全局的排序,因此只有一個reducer,會導致當輸入規模較大時,需要較長的計算時間。sort by
不是全局排序,其在數據進入reducer前完成排序。因此,如果用sort by
進行排序,則sort by
只保證每個reducer的輸出有序,不保證全局有序。distribute by 欄位
根據指定的欄位將數據分到不同的reducer,且分發演算法是hash散列,常用sort by
結合使用,Hive要求distribute by
語句要寫在sort by
語句之前。cluster by 欄位
除了具有distribute by
的功能(既可以把數據分到不同的reduce)外,還會對該欄位進行排序。但是排序只能是倒序排序,不能指定排序規則為asc
或者desc
- 因此:
- 當數據量規模較大時,不使用
order by
,使用用distribute by + sort by
- 如果
distribute by
和sort by
欄位是同一個時,此時,cluster by = distribute by + sort by
- 當數據量規模較大時,不使用
Hive中部分高頻函數 ———— split
/ coalesce
/ collect list
/ collect set
Hive常用函數
Hive 運維
如何監控一個提交後的Hive狀態
- 使用java代碼提交Hive,通過HiveStatement獲取日誌數據並解析出
application_id
- 就可以通過
application_id
去yarn上查看運行狀態
Hive 優化
該模塊請參考我關於Hive優化
的文章
- 點擊訪問 ————> Hive在工作中的調優總結
- 點擊訪問 ————> HiveSQL工作實戰總結
我是 fx67ll.com,如果您發現本文有什麼錯誤,歡迎在評論區討論指正,感謝您的閱讀!
如果您喜歡這篇文章,歡迎訪問我的 本文github倉庫地址,為我點一顆Star,Thanks~