hive從查詢中獲取數據插入到表或動態分區

Hive的insert語句可以從查詢語句中獲取數據,並同時將數據Load到目標表中。如今假定有一個已有數據的表staged_employees(僱員信息全量表),所屬國家cnty和所屬州st是該表的兩個屬性,咱們作個試驗將該表中的數據查詢出來插入到另外一個表employees中。node

INSERT OVERWRITE TABLE employees
PARTITION (country = '中國', state = '北京')
SELECT * FROM staged_employees se
WHERE se.cnty = '中國' AND se.st = '北京';

因爲使用了OVERWRITE關鍵字,目標表中原來相同partition中的全部數據被覆蓋,若是目標表中沒有partition,則整個表會被覆蓋。sql

若是把OVERWRITE關鍵字刪掉,或者替換成INTO,則hive會追加而不是替代原分區或原表中的數據,這個特性在Hive v0.8.0以後才支持。app

當數據已經存在於hdfs上但不是咱們想要的格式的時候,當進行的計算須要分好多步驟有必要存儲中間數據的時候,或者原數據沒有分區、有不少無效列須要過濾的時候,可使用insert..select句型來完成這一轉換過程。oop

因爲一個國家有不少個省份,若是想根據(國家country,地區partition)兩個維度對數據進行分區的話,這條SQL語句的執行個數應該等於地區的數目,好比中國有23個省就要對該SQL語句執行23次。所以hive對這個SQL語句進行了改造,只須要掃描一次原表就能夠生成不一樣的輸出(多路輸出)。好比下面的SQL語句掃描了一次原始數據表,可是同時生成了3個省份的結果數據:spa

FROM staged_employees se
INSERT OVERWRITE TABLE employees
	PARTITION (country = '中國', state = '河北省')	
	SELECT * WHERE se.cnty = '中國' AND se.st = '河北省'
INSERT OVERWRITE TABLE employees
	PARTITION (country = '中國', state = '陝西省')	
	SELECT * WHERE se.cnty = '中國' AND se.st = '陝西省'
INSERT OVERWRITE TABLE employees
	PARTITION (country = '中國', state = '河南省')	
	SELECT * WHERE se.cnty = 'US' AND se.st = '河南省';

經過縮進能夠很清楚的看到,咱們掃描了一次staged_employees表可是執行了3次不一樣的insert語句,這條大SQL語句是這麼執行的:先經過from staged_employees表獲取一條記錄,而後執行每個select子句,若是select子句驗證經過則執行相應的insert語句。注意這裏的三條select子句是徹底獨立執行的,並非if .. then .. else的關係,這就意味着這3條select子句在某種狀況下可能同時經過where檢測。設計

經過這種結構,原始表的數據能被拆分到目標表的不一樣partition中去。code

若是原表的一條記錄知足於其中一個給定的select .. where .. 子句,則該記錄將被寫到目標表的固定分區中。其實更進一步,每條Insert語句能將數據寫到不一樣的數據表中,無論這個表是否分區都同樣。orm

因而,就像一個過濾器同樣,原表的一些數據被寫到了不少輸出地址,而剩下的數據會被丟棄。hadoop

固然,你也能夠混用Insert overwrite和insert into兩種不一樣的方法寫出數據。ci

向動態分區插入數據

可是問題仍是沒有解決,中國有23個省,那麼咱們就須要寫23個insert into .. select ..where子句,這很是不現實。因而hive的一種叫作動態分區的特性就出現了,它可以根據select出來的參數自動推斷將數據插入到那個分區中去。本文上面的兩種SQL語句設定分區的方式都叫作靜態分區插入。

將上一個SQL語句進行改動,會獲得如下簡潔的新SQL語句:

INSERT OVERWRITE TABLE employees
PARTITION (country, state)
SELECT ..., se.cnty, se.st
FROM staged_employees se;

hive先獲取select的最後兩個位置的se.cnty和se.st參數值,而後將這兩個值填寫到Insert語句partition中的兩個country和state變量中,即動態分區是經過位置來對應分區值的。原始表select出來的值和輸出partition的值的關係僅僅是經過位置來肯定的,和名字並無關係,好比這裏se.cnty和county的名稱徹底沒有關係。

上面的這條SQL語句是對兩個分區同時進行了動態設定,若是staged_employees表中有100個國家,每一個國家有100個地區,那麼該SQL語句自動對每一個國家和地區創建相應的partition並插入數據,若是用手寫的話不現實。

只要位置正確,你能夠混用動態分區和靜態分區值設定,好比下面這個例子,你能夠靜態指定一個country值,可是state值採用動態的方法設定:

INSERT OVERWRITE TABLE employees
PARTITION (country = 'US', state)
SELECT ..., se.cnty, se.stFROM staged_employees se
WHERE se.cnty = 'US';

使用hive動態分區的參數設定

動態分區功能默認是關閉的,而當它是打開狀態時,默認會工做在「strict」模式下,這種模式下要求至少指定一個靜態分區的值。這樣作是爲了防止設計了大量partition的糟糕狀況,舉個例子你使用時間戳來進行分區,居然每一秒鐘都產生一個分區!還有其餘的一些屬性設定用來限制相似的狀況出現,以下表所示:

名稱 默認值 描述
hive.exec.dynamic.partition false 設置爲true用於打開動態分區功能
hive.exec.dynamic.partition.mode strict 設置爲nonstrict可以讓全部的分區都動態被設定,不然的話至少須要指定一個分區值
hive.exec.max.dynamic.partitions.pernode 100 能被每一個mapper或者reducer建立的最大動態分區的數目,若是一個mappre或者reducer試圖建立多餘這個值的動態分區數目,會引起錯誤
hive.exec.max.dynamic.partitions +1000 被一條帶有動態分區的SQL語句所能建立的動態分區總量,若是超出限制會報出錯誤
hive.exec.max.created.files 100000 全局能被建立文件數目的最大值,專門有一個hadoop計數器來跟蹤該值,若是超出會報錯

舉個例子,使用全動態分區的SQL語句序列以下所示,須要先設定一些必要的參數才能夠:

set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
set hive.exec.max.dynamic.partitions.pernode=1000;
INSERT OVERWRITE TABLE employees
PARTITION (country, state)
SELECT ..., se.cty, se.st
FROM staged_employees se;

總結

使用from .. insert.. select ..where結構可以從一個數據表中抽取數據,將結果插入到不一樣的表和分區中,而使用動態分區可以讓hive根據select最末幾個位置的值自動設定目標分區的值,使用動態分區須要設定一些hive運行參數

相關文章
相關標籤/搜索