Hive 系列(七)—— Hive 常用 DML 操作
一、載入檔案資料到表
1.1 語法
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE]
INTO TABLE tablename [PARTITION (partcol1=val1,partcol2=val2 ...)]
複製程式碼
-
LOCAL
關鍵字代表從本地檔案系統載入檔案,省略則代表從 HDFS 上載入檔案:
-
從本地檔案系統載入檔案時,
filepath
可以是絕對路徑也可以是相對路徑 (建議使用絕對路徑); -
從 HDFS 載入檔案時候,
filepath
為檔案完整的 URL 地址:如hdfs://namenode:port/user/hive/project/ data1
-
filepath
可以是檔案路徑 (在這種情況下 Hive 會將檔案移動到表中),也可以目錄路徑 (在這種情況下,Hive 會將該目錄中的所有檔案移動到表中); -
如果使用 OVERWRITE 關鍵字,則將刪除目標表(或分割槽)的內容,使用新的資料填充;不使用此關鍵字,則資料以追加的方式加入;
-
載入的目標可以是表或分割槽。如果是分割槽表,則必須指定載入資料的分割槽;
-
載入檔案的格式必須與建表時使用
STORED AS
指定的儲存格式相同。
使用建議:
不論是本地路徑還是 URL 都建議使用完整的。雖然可以使用不完整的 URL 地址,此時 Hive 將使用 hadoop 中的 fs.default.name 配置來推斷地址,但是為避免不必要的錯誤,建議使用完整的本地路徑或 URL 地址;
載入物件是分割槽表時建議顯示指定分割槽。在 Hive 3.0 之後,內部將載入 (LOAD) 重寫為 INSERT AS SELECT,此時如果不指定分割槽,INSERT AS SELECT 將假設最後一組列是分割槽列,如果該列不是表定義的分割槽,它將丟擲錯誤。為避免錯誤,還是建議顯示指定分割槽。
1.2 示例
新建分割槽表:
CREATE TABLE emp_ptn(
empno INT,ename STRING,job STRING,mgr INT,hiredate TIMESTAMP,sal DECIMAL(7,2),comm DECIMAL(7,2)
)
PARTITIONED BY (deptno INT) -- 按照部門編號進行分割槽
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
複製程式碼
從 HDFS 上載入資料到分割槽表:
LOAD DATA INPATH "hdfs://hadoop001:8020/mydir/emp.txt" OVERWRITE INTO TABLE emp_ptn PARTITION (deptno=20);
複製程式碼
emp.txt 檔案可在本倉庫的 resources 目錄中下載
載入後表中資料如下,分割槽列 deptno 全部賦值成 20:
二、查詢結果插入到表
2.1 語法
INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1,partcol2=val2 ...) [IF NOT EXISTS]]
select_statement1 FROM from_statement;
INSERT INTO TABLE tablename1 [PARTITION (partcol1=val1,partcol2=val2 ...)]
select_statement1 FROM from_statement;
複製程式碼
-
Hive 0.13.0 開始,建表時可以通過使用 TBLPROPERTIES(“immutable”=“true”)來建立不可變表 (immutable table) ,如果不可以變表中存在資料,則 INSERT INTO 失敗。(注:INSERT OVERWRITE 的語句不受
immutable
屬性的影響); -
可以對錶或分割槽執行插入操作。如果表已分割槽,則必須通過指定所有分割槽列的值來指定表的特定分割槽;
-
從 Hive 1.1.0 開始,TABLE 關鍵字是可選的;
-
從 Hive 1.2.0 開始 ,可以採用 INSERT INTO tablename(z,x,c1) 指明插入列;
-
可以將 SELECT 語句的查詢結果插入多個表(或分割槽),稱為多表插入。語法如下:
FROM from_statement INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1,partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 [INSERT OVERWRITE TABLE tablename2 [PARTITION ... [IF NOT EXISTS]] select_statement2] [INSERT INTO TABLE tablename2 [PARTITION ...] select_statement2] ...; 複製程式碼
2.2 動態插入分割槽
INSERT OVERWRITE TABLE tablename PARTITION (partcol1[=val1],partcol2[=val2] ...)
select_statement FROM from_statement;
INSERT INTO TABLE tablename PARTITION (partcol1[=val1],partcol2[=val2] ...)
select_statement FROM from_statement;
複製程式碼
在向分割槽表插入資料時候,分割槽列名是必須的,但是列值是可選的。如果給出了分割槽列值,我們將其稱為靜態分割槽,否則它是動態分割槽。動態分割槽列必須在 SELECT 語句的列中最後指定,並且與它們在 PARTITION() 子句中出現的順序相同。
注意:Hive 0.9.0 之前的版本動態分割槽插入是預設禁用的,而 0.9.0 之後的版本則預設啟用。以下是動態分割槽的相關配置:
配置 | 預設值 | 說明 |
---|---|---|
hive.exec.dynamic.partition |
true |
需要設定為 true 才能啟用動態分割槽插入 |
hive.exec.dynamic.partition.mode |
strict |
在嚴格模式 (strict) 下,使用者必須至少指定一個靜態分割槽,以防使用者意外覆蓋所有分割槽,在非嚴格模式下,允許所有分割槽都是動態的 |
hive.exec.max.dynamic.partitions.pernode |
100 | 允許在每個 mapper/reducer 節點中建立的最大動態分割槽數 |
hive.exec.max.dynamic.partitions |
1000 | 允許總共建立的最大動態分割槽數 |
hive.exec.max.created.files |
100000 | 作業中所有 mapper/reducer 建立的 HDFS 檔案的最大數量 |
hive.error.on.empty.partition |
false |
如果動態分割槽插入生成空結果,是否丟擲異常 |
2.3 示例
- 新建 emp 表,作為查詢物件表
CREATE TABLE emp(
empno INT,deptno INT)
ROW FORMAT DELIMITED FIELDS TERMINATED BY "\t";
-- 載入資料到 emp 表中 這裡直接從本地載入
load data local inpath "/usr/file/emp.txt" into table emp;
複製程式碼
完成後 emp
表中資料如下:
- 為清晰演示,先清空
emp_ptn
表中載入的資料:
TRUNCATE TABLE emp_ptn;
複製程式碼
- 靜態分割槽演示:從
emp
表中查詢部門編號為 20 的員工資料,並插入emp_ptn
表中,語句如下:
INSERT OVERWRITE TABLE emp_ptn PARTITION (deptno=20)
SELECT empno,ename,job,mgr,hiredate,sal,comm FROM emp WHERE deptno=20;
複製程式碼
完成後 emp_ptn
表中資料如下:
- 接著演示動態分割槽:
-- 由於我們只有一個分割槽,且還是動態分割槽,所以需要關閉嚴格預設。因為在嚴格模式下,使用者必須至少指定一個靜態分割槽
set hive.exec.dynamic.partition.mode=nonstrict;
-- 動態分割槽 此時查詢語句的最後一列為動態分割槽列,即 deptno
INSERT OVERWRITE TABLE emp_ptn PARTITION (deptno)
SELECT empno,comm,deptno FROM emp WHERE deptno=30;
複製程式碼
完成後 emp_ptn
表中資料如下:
三、使用SQL語句插入值
INSERT INTO TABLE tablename [PARTITION (partcol1[=val1],partcol2[=val2] ...)]
VALUES ( value [,value ...] )
複製程式碼
- 使用時必須為表中的每個列都提供值。不支援只向部分列插入值(可以為預設值的列提供空值來消除這個弊端);
- 如果目標表表支援 ACID 及其事務管理器,則插入後自動提交;
- 不支援支援複雜型別 (array,map,struct,union) 的插入。
四、更新和刪除資料
4.1 語法
更新和刪除的語法比較簡單,和關係型資料庫一致。需要注意的是這兩個操作都只能在支援 ACID 的表,也就是事務表上才能執行。
-- 更新
UPDATE tablename SET column = value [,column = value ...] [WHERE expression]
--刪除
DELETE FROM tablename [WHERE expression]
複製程式碼
4.2 示例
1. 修改配置
首先需要更改 hive-site.xml
,新增如下配置,開啟事務支援,配置完成後需要重啟 Hive 服務。
<property>
<name>hive.support.concurrency</name>
<value>true</value>
</property>
<property>
<name>hive.enforce.bucketing</name>
<value>true</value>
</property>
<property>
<name>hive.exec.dynamic.partition.mode</name>
<value>nonstrict</value>
</property>
<property>
<name>hive.txn.manager</name>
<value>org.apache.hadoop.hive.ql.lockmgr.DbTxnManager</value>
</property>
<property>
<name>hive.compactor.initiator.on</name>
<value>true</value>
</property>
<property>
<name>hive.in.test</name>
<value>true</value>
</property>
複製程式碼
2. 建立測試表
建立用於測試的事務表,建表時候指定屬性 transactional = true
則代表該表是事務表。需要注意的是,按照官方檔案 的說明,目前 Hive 中的事務表有以下限制:
- 必須是 buckets Table;
- 僅支援 ORC 檔案格式;
- 不支援 LOAD DATA ...語句。
CREATE TABLE emp_ts(
empno int,ename String
)
CLUSTERED BY (empno) INTO 2 BUCKETS STORED AS ORC
TBLPROPERTIES ("transactional"="true");
複製程式碼
3. 插入測試資料
INSERT INTO TABLE emp_ts VALUES (1,"ming"),(2,"hong");
複製程式碼
插入資料依靠的是 MapReduce 作業,執行成功後資料如下:
4. 測試更新和刪除
--更新資料
UPDATE emp_ts SET ename = "lan" WHERE empno=1;
--刪除資料
DELETE FROM emp_ts WHERE empno=2;
複製程式碼
更新和刪除資料依靠的也是 MapReduce 作業,執行成功後資料如下:
五、查詢結果寫出到檔案系統
5.1 語法
INSERT OVERWRITE [LOCAL] DIRECTORY directory1
[ROW FORMAT row_format] [STORED AS file_format]
SELECT ... FROM ...
複製程式碼
-
OVERWRITE 關鍵字表示輸出檔案存在時,先刪除後再重新寫入;
-
和 Load 語句一樣,建議無論是本地路徑還是 URL 地址都使用完整的;
-
寫入檔案系統的資料被序列化為文字,其中列預設由^A 分隔,行由換行符分隔。如果列不是基本型別,則將其序列化為 JSON 格式。其中行分隔符不允許自定義,但列分隔符可以自定義,如下:
-- 定義列分隔符為'\t' insert overwrite local directory './test-04' row format delimited FIELDS TERMINATED BY '\t' COLLECTION ITEMS TERMINATED BY ',' MAP KEYS TERMINATED BY ':' select * from src; 複製程式碼
5.2 示例
這裡我們將上面建立的 emp_ptn
表匯出到本地檔案系統,語句如下:
INSERT OVERWRITE LOCAL DIRECTORY '/usr/file/ouput'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
SELECT * FROM emp_ptn;
複製程式碼
匯出結果如下:
參考資料
更多大資料系列文章可以參見 GitHub 開源專案: 大資料入門指南