一、DDL操作(定義操作)
1、創建表
(1)建表語法結構
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)] //字段注釋
[COMMENT table_comment] //表的注釋
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)] //分區,前面沒有出現的字段
[CLUSTERED BY (col_name, col_name, ...) //分桶,前面出現的字段
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
分區:不用關注數據的具體類型,放入每一個分區里; 分桶:調用哈希函數取模的方式進行分桶
(2)建表語句相關解釋
create table: 創建一個指定名字的表。如果相同名字的表已經存在,則拋出異常;用 戶可以用 IF NOT EXISTS 選項來忽略這個異常。
external :關鍵字可以讓用戶創建一個外部表,在建表的同時指定一個指向實際數據的 路徑( LOCATION), Hive 創建內部表時,會將數據移動到數據倉庫指向的路徑;若創建 外部表,僅記錄數據所在的路徑,不對數據的位置做任何改變。在刪除表的時候,內部
表的元數據和數據會被一起刪除,而外部表只刪除元數據,不刪除數據。 (經典面試問題)
partitioned :在 Hive Select 查詢中一般會掃描整個表內容,會消耗很多時間做沒必要的 工作。有時候只需要掃描表中關心的一部分數據,因此建表時引入了 partition 概念。 個 表可以擁有一個或者多個分區,每個分區以文件夾的形式單獨存在表文件夾的目錄下,
分區是以字段的形式在表結構中存在,通過 desc table 命令可以查看到字段存在,但是 該字段不存放實際的數據內容,僅僅是分區的表示。分區建表分為 2 種,一種是單分區, 也就是說在表文件夾目錄下只有一級文件夾目錄。另外一種是多分區,表文件夾下出現
多文件夾嵌套模式
like: 允許用戶復制現有的表結構,但是不復制數據。
comment: 可以為表與字段增加描述
row format:
stored as :如果文件數據是純文本,可以使用 STORED AS TEXTFILE。如果數據需要壓縮,使用 STORED AS SEQUENCEFILE。
clustered by (分桶):
location:指定數據文件存放的 hdfs 目錄
(3)hive的建表示例
執行查看表結構:desc formatted page_view
(4)Hive QL對SQL語句的支持
1、 select * from db.table1
2、 select count(distinct uid) from db.table1
3、 支持 select、 union all、 join( left、 right、 full join)、 like、 where、各種聚合函數、支 持 json 解析
4、 UDF( User Defined Function) / UDAF(多行合並為一行)
5、 不支持 update 和 delete
6、 hive 支持 in/exists, hive 使用 semi join 的方式來代替實現,而且效率更高。
(5)具體示例
a、創建內部表
create table mytable (id int, name string) row format delimited fields terminated by ','
stored as textfile;
b、創建外部表
create external table mytable2 (id int, name string) row format delimited fields
terminated by ',' location '/user/hive/warehouse/mytable2';
c、創建分區表
create table mytable3(id int, name string)
partitioned by(sex string) row format delimited fields terminated by ','stored as textfile;
插入數據
插入男分區數據: load data local inpath '/root/hivedata/mingxing.txt' overrite into table
mytable3 partition(sex='boy');
插入女分區數據: load data local inpath '/root/hivedata/mingxing.txt' overrite into table
mytable3 partition(sex='girl');
d、創建分桶表
create table stu_buck(Sno int,Sname string,Sex string,Sage int,Sdept string)
clustered by(Sno) sorted by(Sno DESC) into 4 buckets
row format delimited fields terminated by ',';
2、修改表
(1)重命名表 ALTER TABLE table_name RENAME TO new_table_name
(2)增加、刪除、改變、替換列
(3)刪除表 DROP TABLE [IF EXISTS] table_name;
(4)增加、刪除分區
增加分區語法結構:
ALTER TABLE table_name ADD [IF NOT EXISTS] partition_spec [ LOCATION 'location1' ]
partition_spec [ LOCATION 'location2' ] ...
刪除分區語法結構:ALTER TABLE table_name DROP partition_spec, partition_spec,...
具體示例:alter table student_p add partition(part='a') partition(part='b');
顯示命令:
show tables;
show databases;
show partitions table_name;
show functions; 展示內置函數
desc extended table_name;
desc formatted table_name;
二、DML操作
1、load裝載數據 LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
說明:
(1) Load 操作只是單純的復制/移動操作,將數據文件移動到 Hive 表對應的位置。
(2) filepath:
相對路徑,例如: project/data1
絕對路徑,例如: /user/hive/project/data1
包含模式的完整 URI,列如:
hdfs://namenode_host:9000/user/hive/project/data1
(3) local 關鍵字
如果指定了 LOCAL, load 命令會去查找本地文件系統中的 filepath。
如果沒有指定 LOCAL 關鍵字,則根據 inpath 中的 uri 查找文件
注意: uri 是指 hdfs 上的路徑,分簡單模式和完整模式兩種,例如:
簡單模式: /user/hive/project/data1
完整模式: hdfs://namenode_host:9000/user/hive/project/data1
(4)overwrite 關鍵字
如果使用了 OVERWRITE 關鍵字,則目標表(或者分區)中的內容會被刪除,然后再將 filepath 指向的文件/目錄中的內容添加到表/分區中。
如果目標表(分區)已經有一個文件,並且文件名和 filepath 中的文件名沖突,那么現 有的文件會被新文件所替代。
2、insert 插入數據
(1)插入一條數據 INSERT INTO TABLE table_name VALUES(XX,YY,ZZ);
(2)利用查詢語句將結果導入新表:
INSERT OVERWRITE [INTO] TABLE table_name [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement1 FROM from_statement
(3)多重插入
FROM from_statement
INSERT OVERWRITE TABLE table_name1 [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement1
INSERT OVERWRITE TABLE table_name2 [PARTITION (partcol1=val1, partcol2=val2 ...)]
select_statement2] ...
示例:從 mingxing 表中,按不同的字段進行查詢得的結果分別插入不同的 hive 表
from mingxing insert into table mingxing2 select id,name,sex,age insert into table mingxing select
id,name,sex ,age,department ;
(4)分區插入
分區插入有兩種,一種是靜態分區,另一種是動態分區。如果混合使用靜態分區和動態分區, 則靜態分區必須出現在動態分區之前。現分別介紹這兩種分區插入。
靜態分區:創建靜態分區表、從查詢結果中導入數據、查看插入結果
動態分區:
靜態分區需要創建非常多的分區,那么用戶就需要寫非常多的 SQL! Hive 提供了一個動態分 區功能,其可以基於查詢參數推斷出需要創建的分區名稱。
A)、創建分區表,和創建靜態分區表是一樣的
B)、 參數設置
hive> set hive.exec.dynamic.partition=true;
hive> set hive.exec.dynamic.partition.mode=nonstrict;
注意: 動態分區默認情況下是沒有開啟的。開啟后,默認是以”嚴格“模式執行的,在
這種模式下要求至少有一列分區字段是靜態的。這有助於阻止因設計錯誤導致查詢產生
大量的分區。但是此處我們不需要靜態分區字段,估將其設為 nonstrict。
C)、 動態數據插入 (partition字段必須出現在select字段的最后)
insert into table test2 partition (age) select name,address,school,age from students;
注意:查詢語句 select 查詢出來的 age 字段必須放在最后,和分區字段對應,不然結果
會出錯
D)、 查看插入結果
(5)case(create table ... as select..)
在實際情況中,表的輸出結果可能太多,不適於顯示在控制台上,這時候,將 Hive 的查 詢輸出結果直接存在一個新的表中是非常方便的,我們稱這種情況為 CTAS
展示:
CREATE TABLE mytest AS SELECT name, age FROM test;
注意: CTAS 操作是原子的,因此如果 select 查詢由於某種原因而失敗,新表是不會創建 的!
3、insert 導出數據 (如果有local 導出到本地,不帶local,導入HDFS)
單模式導出:
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement
多模式導出:
FROM from_statement
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1
[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...
具體示例:
導出數據到本地 Insert overwrite local directory '/root/hivedata/student.txt' select * from studentss;
注意: 數據寫入到文件系統時進行文本序列化,且每列用^A 來區分, \n 為換行符。用
more 命令查看時不容易看出分割符,可以使用: sed -e 's/\x01/|/g' filename 來查看。
導出數據到HDFS: Insert overwrite directory 'hdfs://hadoop02:9000/user/hive/warehouse/mystudent' select * from studentss;
4、select 查詢數據
語法結構:
SELECT [ALL | DISTINCT] select_ condition, select_ condition, ...
FROM table_name a
[JOIN table_other b ON a.id = b.id]
[WHERE where_condition]
[GROUP BY col_list [HAVING condition]]
[CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list | ORDER BY col_list] ]
[LIMIT number]
說明:
(1)select_ condition 查詢字段
(2)table_name 表名
(3) order by 會對輸入做全局排序,因此只有一個 reducer,只有一個 reduce task 的結果, 比如文件名是 000000_0,會導致當輸入規模較大時,需要較長的計算時間。
(4) sort by 不是全局排序,其在數據進入 reducer 前完成排序。因此,如果用 sort by 進行排 序,並且設置 mapred.reduce.tasks>1,則 sort by 只保證每個 reducer 的輸出有序,不保 證全局有序。
那萬一,我要對我的所有處理結果進行一個綜合排序,而且數據量又非常大,那么怎么 解決?
我們不適用 order by 進行全數據排序,我們適用 sort by 對數據進行局部排序,完了之 后,再對所有的局部排序結果做一個歸並排序
(5)distribute by(字段)根據指定的字段將數據分到不同的 reducer,且分發算法是 hash 散列。
(6)Cluster by(字段) 除了具有 Distribute by 的功能外,還會對該字段進行排序。
因此,如果分桶和 sort 字段是同一個時,此時, clustered by = distribute by + sort by 如果我們要分桶的字段和要排序的字段不一樣,那么我們就不能適用 clustered by
分桶表的作用:最大的作用是用來提高 join 操作的效率;
( 思考這個問題: select a.id,a.name,b.addr from a join b on a.id = b.id;如果 a 表和 b 表已經是 分桶表,而且分桶的字段是 id 字段做這個 join 操作時,還需要全表做笛卡爾積嗎)
實例:(1)獲取年齡大的三個學生
select id ,age,name from student where stat_date='20140101' order by age desc limit 3;
(2)查詢學生年齡,按降序排序
select id,age,name from student sort by age desc;
select id,age,name from student order by age desc;
select id,age,name from student distribute by age;
這是分桶和排序的組合操作,對 id 進行分桶,對 age, id 進行降序排序
insert overwrite directory '/root/outputdata6' select * from mingxing2 distribute by id sort
by age desc, id desc;
這是分桶操作,按照 id 分桶,但是不進行排序
insert overwrite directory '/root/outputdata4' select * from mingxing2 distribute by id sort
by age;
這是分桶操作,按照 id 分桶,並且按照 id 排序
insert overwrite directory '/root/outputdata3' select * from mingxing2 cluster by id;
分桶查詢:
指定開啟分桶:
set hive.enforce.bucketing = true;
指定 reducetask 數量,也就是指定桶的數量
set mapreduce.job.reduces=4;
insert overwrite directory '/root/outputdata3' select * from mingxing2 cluster by id;
(3)按學生名稱匯總學生年齡
select name ,sum(age) from student group by name;
解釋三個執行參數:
直接使用不帶設置值得時候是可以查看到這個參數的默認值:
set hive.exec.reducers.bytes.per.reducer
hive.exec.reducers.bytes.per.reducer:一個 hive,就相當於一次 hive 查詢中,每一個 reduce
任務它處理的平均數據量
如果要改變值,我們使用這種方式:
set hive.exec.reducers.bytes.per.reducer=51200000
查看設置的最大 reducetask 數量
set hive.exec.reducers.max
hive.exec.reducers.max:一次 hive 查詢中,最多使用的 reduce task 的數量
我們可以這樣使用去改變這個值:
set hive.exec.reducers.max = 20
查看設置的一個 reducetask 常量數量
set mapreduce.job.reduces
mapreduce.job.reduces:我們設置的 reducetask 數量
三個參數的優先級順序是:
mapreduce.job.reduces > hive.exec.reducers.max > hive.exec.reducers.bytes.per.reducer
補充:
// 創建內部表 student create table student(id int, name string, sex string, age int, department string) row format delimited fields terminated by ',' //行分隔符用 lines stored as textfile; // 從本地導入數據 load data local inpath '/home/hadoop/student.txt' into table student; // 查詢數據 select id, name, sex, age, department from student; // 創建一個external表 create external table ext_student(id int, name string, sex string, age int, department string) row format delimited fields terminated by ',' location '/ext_student'; // 導入數據 hadoop fs -put student.txt /ext_student; load data local inpath '/home/hadoop/mingxing.txt' into table ext_student; // 查詢數據 select id, name ,sex, age , department from ext_student; // 創建內部表引用外部路徑 create table mng_student(id int, name string, sex string, age int, department string) row format delimited fields terminated by ',' location '/ext_student'; // 創建分區表 create table ptn_student(id int, name string, sex string, age int, department string) partitioned by(code string) row format delimited fields terminated by ','; // 往分區表導入數據 load data local inpath '/home/hadoop/student.txt' into table ptn_student partition(code='112233'); load data local inpath '/home/hadoop/student.txt' into table ptn_student1 partition(code='335566'); // 創建多字段分區表 create table ptn_student1(id int, name string, sex string, age int, department string) partitioned by(code string, province string) row format delimited fields terminated by ','; // 往多分區表導入數據,需指定兩個分區字段值 load data local inpath '/home/hadoop/student.txt' into table ptn_student1 partition(code='335566', province='beijing'); load data local inpath '/home/hadoop/student.txt' into table ptn_student1 partition(code='335566', province='tianjing'); load data local inpath '/home/hadoop/student.txt' into table ptn_student1 partition(code='kk', province='tianjing'); // 創建分桶表 create table bck_student(id int, name string, sex string, age int, department string) clustered by(department) into 4 buckets row format delimited fields terminated by ','; // 重命名表 alter table student rename to studentss; // 修改表的字段 alter table studentss add columns(abc string, efg int); // 刪除表的字段,有一些問題。drop字段有問題。不確定能不能執行成功 alter table studentss drop column efg; // 修改表的字段 alter table studentss change abc code int; // 修改表的字段,並且改變字段的位置 alter table studentss change efg province string after name; // 替換所有字段 alter table studentss replace columns(id int, name string, sex string , age int , department string); // 刪除表 drop table bck_student; drop table if exists bck_student; // 添加分區 alter table ptn_student add partition(code='445566'); alter table ptn_student add partition(code='445566') partition(code='778899'); // 刪除分區 alter table ptn_student drop partition(code='445566'); // insert ... select ..... insert into table student select id, name, sex, age, department from studentss where department = 'MA'; // 以下兩句操作是為多重插入准備兩張表 create table student11(id int, name string) row format delimited fields terminated by ',' stored as textfile; create table student22(sex string, age int, department string) row format delimited fields terminated by ',' stored as textfile; // 多重插入 from studentss insert into table student11 select id, name insert into table student22 select sex, age, department; // 靜態分區插入 load data local inpath 'student.txt' into table ptn_student partition(code='112233'); // 動態分區插入 set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; insert into table d_student partition(age) select id, name, sex, department,age from studentss; // 創建一個分區表,為上面的動態分區做准備的 create table d_student(id int, name string, sex string ,department string) partitioned by(age int) row format delimited fields terminated by ','; // CTAS create table my_student as select id, name , sex, age, department from studentss; // like create table like_student like studentss; // insert導出hive表數據到本地 insert overwrite local directory '/home/hadoop/myoutput' select id, name, sex, age, department from studentss;