Hive
启动准备
-  
启动hadoop
start-all.sh -  
mysql
service mysqld start #建议:把mysqld服务设置为开机自启动 chkconfig mysqld on -  
安全模式中->等待几秒->确认不是安全模式后再下一步
 -  
启动hive服务
nohup /export/servers/hive/bin/hive --service metastore &nohup /export/servers/hive/bin/hive --service hiveserver2 & -  
客户端连接
/export/servers/hive/bin/beeline! connect jdbc:hive2://node-1:10000 root@hadoop 
DDL-创建数据库
show databases;
create database kyletest;
use kyletest;
 
创建表-指定分隔符
内部表
-  
语法格式
 
row format [delimited | serde]
#row format :表明指定分隔符
#delimited:表明实现默认的SerDe类来进行分隔符指定  默认就是LazySimpleSerDe
#serde :表明使用其他的类进行分隔符指定
 
-  
delimited具体语法
 
[fields terminated by char]   --指定字段之间的分隔符
[collection items terminated by char] --指定集合元素之间的分隔符
[map keys terminated by char]         --指定map类型 kv之间是分隔符
[lines terminated by char]            --指定换行符
 
- 创建表1:
 
create table users(id int,name string,age int) row format delimited fields terminated by ',';	
 
hadoop fs -put users.txt /user/hive/warehouse/kyletest.db/users
 
select * from users;
+-----------+--------------+------------+----------------+--+
| users.id  | users.uname  | users.age  | users.address  |
+-----------+--------------+------------+----------------+--+
| 1         | kyle         | 18         | sz             |
| 2         | ben          | 20         | bj             |
| 3         | hana         | 21         | cs             |
| 4         | xixi         | 22         | sc             |
+-----------+--------------+------------+----------------+--+
select count(*) from users where age > 20;
巨慢
 
- 创建表2:
 
create table t_arr(name string, works array<string>) row format delimited fields terminated by '\t' collection items terminated by ',';
 
select * from t_arr;
+-------------+----------------------------------------------+--+
| t_arr.name  |                 t_arr.works                  |
+-------------+----------------------------------------------+--+
| zhangsan    | ["beijing","shanghai","tianjin","hangzhou"]  |
| wangwu      | ["shanghai","chengdu","wuhan","haerbin"]     |
+-------------+----------------------------------------------+--+
select works[2] from t_arr;
+----------+--+
|   _c0    |
+----------+--+
| tianjin  |
| wuhan    |
+----------+--+
 
Q: 执行流程?
hive sql > MapReduce > 处理数据
 
Q: 表的字段类型 个数 顺序 要不要和文件保持一致?
必须一致
 
Q: 创建表时类型是否要保持一致?
建表的时候 hive的数据类型要和文件中类型保持一致。
如果不一致,hive会尝试转换,不保证转换成功。
如果不成功,就显示null。
 
Q: 结构化文件在hdfs上的位置能否任意存放?
可以
 
Q: 还是需要放置在指定的位置?
/user/hive/warehouse/库名.db/表名
 
Q: hive的数据类型?
- hive除了支持sql类型之外 ,还支持java数据类型。
- hive数据类型字面 大小写不明感。
- hive除了支持基本数据类型之外 还支持复杂类型  比如:Array  Map
-- 在使用复杂类型的时候  一定要配合分隔符的指定语法来使用。
 
Q: hive常见两种错误?
Error while compiling statement。 #编译期间的错误  sql语法错误
Error while processing statement. #执行期间的错误  逻辑上的错误
 
Q: hive的读取文件映射的原理
1. - 首先通过InputFormat类来读取文件,默认实现==TextInputFormat==。
	  一行一行的读取数据。
2. - 然后通过SerDe类根据分隔符进行一行内容切割,默认实现LazySimpleSerDe。
	SerDe == (serialization/deserialization)
  切割出来一个字段 对应表的一个字段 完成映射
 
Q: hive的默认分隔符?
-- 如果在建表的时候 没有指定row format。此时就会采用默认分隔符创建表。
-- 如果映射的文件中分隔符也是hive的默认分隔符,就会存在不指定分隔符也会映射成功。
-- hive的默认分隔符是一种不可见分隔符  代码\001
-- 在vim编辑器中  连续输入ctrl+V  ctrl+A
 
外部表
create external table … location
create external table t_flowcount(id string, phone string, mac string) row format delimited fields terminated by '\t' location '/flowCount/input';
 
--注意:
如果在建表的时候 有关键字external  创建的就是外部表  否则就是内部表
外部表的位置可以位于hdfs的任意路径  可以通过location 关键字指定清楚。
外部表如果不指定location 默认也是在hive默认路径下/user/hive/warehouse/库名/表名
-- 企业中 一般喜欢创建外部表 但是不指定location。
-- 内部表也称之为管理表(manage table 受hive管理的表)
 
Q: 内外部最大的区别(删除表的时候)?
--如果删除的是内部表
	hive表定义信息连同其映射的结构化数据文件 一起被删除。
--如果删除的是外部表
	只会删除hive中表的定义信息  结构化文件不会被删除的
 
Q: hive表和多个文件之间的映射问题?
一个表下面可以映射多个文件
要保证各个文件之间的结构:字段顺序、类型、个数和表定义的一致
如果不一致  能成功显示 不能成功显示null。
 
分区表
… partitioned by(xx xx)
-- 创建外部分区表
create external table t_user_p(id int, name string, country string) partitioned by(nationality string) row format delimited fields terminated by ',';
-- 上传数据
load data local inpath '/export/data/hivedata/china.txt' into table t_user_p partition(nationality="zh");
load data local inpath '/export/data/hivedata/usa.txt' into table t_user_p partition(nationality="mg");
 
select * from t_user_p;
-- 分区查询
select * from t_user_p where nationality='mg';
select * from t_user_p where nationality='zh';
+--------------+----------------+-------------------+-----------------------+--+
| t_user_p.id  | t_user_p.name  | t_user_p.country  | t_user_p.nationality  |
+--------------+----------------+-------------------+-----------------------+--+
| 1            | zhangsna       | china             | zh                    |
| 2            | lisi           | china             | zh                    |
| 3            | wangwu         | china             | zh                    |
+--------------+----------------+-------------------+-----------------------+--+
 
Q: 为什么需要分区表?
避免全表扫描, 可以查询优化效率,基于分区查询相当于基于文件夹查询
 
Q: 分区表的注意事项?
- 分区表是一种优化表 建表的时候可以不使用。
- 分区表的字段不能是表中已经存在的字段,名字不能重复。 因为分区的字段最终也会显示在查询结果上。
- 分区字段是虚拟的字段  其显示的数据内容并不位于文件中 来自于加载分区表数据的 时候指定的
- 分区表的最终表现形式就是表的文件夹下面  以分区继续创建文件夹  一个分区对应一个文件夹
- 基于不同的文件夹去管理不同分区的数据
- 使用分区字段进行过滤查询的时候 底层直接扫描文件夹即可 不需要全表扫描内容  优化了查询效率
 
多分区表
-- 创建内部多区表
create table t_user_multi(id int, name string, country string) partitioned by(gj string, pro string) row format delimited fields terminated by ',';
-- 上传数据
load data local inpath '/export/data/hivedata/china_bj.txt' into table t_user_multi partition(gj="zh", pro="bj");
load data local inpath '/export/data/hivedata/china_sz.txt' into table t_user_multi partition(gj='zh', pro='sz');
load data local inpath '/export/data/hivedata/usa.txt' into table t_user_multi partition(gj="mg", pro='newyork');
 
select * from t_user_multi where gj='zh' and pro='sz';
+---------+---------------+-------------+-----------+---------+--+
| 	 id   | 		name  		| 	country   | 		gj  	| 	pro   |
+---------+---------------+-------------+-----------+---------+--+
| 4       | lisa          | china       | zh        | sz      |
| 5       | sunyizheng    | china       | zh        | sz      |
| 6       | hanzhimin     | china       | zh        | sz      |
+---------+---------------+-------------+-----------+---------+--+
 
多分区表的总结
- 多分区表目前来说用的比较多的是两个分区。
- 多分区表现形式就是在前一个分区的基础上继续分区  也就是文件夹下面继续创建子文件夹
- 优化查询时候全表扫描
- 常见的分区字段
  -- 时间维度(year month  day)
  -- 地域维度(省市县)
  -- 混合维度(时间+地域)
 
分桶表
clustered by xxx into N buckets
-- 创建分桶表根据sno分为3个部分
create external table t_stubuck(sno int, sname string, sex string, sage int, sdept string) clustered by(sno) into 3 buckets row format delimited fields terminated by ',';
-- 开启分桶查询的功能  并且设定分桶个数  该个数要和分桶表中的个数一致
set hive.enforce.bucketing = true;
set mapreduce.job.reduces=3; --可以不设置默认会根据分桶表信息确定个数
-- 使用分桶查询 把数据从普通临时表中查询插入到最终分桶表中
insert overwrite table [t_stubuck(临时表/自己也行)]
select * from t_stubuck cluster by(Sno);
 
Q: 用分桶表查询的特点?
- 分桶表也是一种优化表  意味着建表的时候可以不使用
- 分桶表的字段必须是表中的字段。
- 分桶表可以去优化减少join查询的笛卡尔积。
 
DDL-修改表
ALTER TABLE
重命名-表
ALTER TABLE … RENAME TO …
ALTER TABLE table_name RENAME TO new_table_name;
 
添加列
alter table … add columns(xx xx);
ALTER TABLE t_flowcount ADD COLUMNS (count string);
 
删除列
alter table … replace columns();
alter table t_flowcount replace columns(id int, name string);
 
修改分区-表
添加分区
alter table … [add | replace] partition(xx=‘xx’) location ‘hdfs://node-21:9000/user/hive/warehouse/key=value’
-- 方式一:
alter table t_user_p add partition(nationality='rb') location '/user/hive/warehouse/kyletest.db/t_user_p/nationality=rb';
load data local inpath '/export/data/hivedata/japan.txt' into table t_user_p partition(nationality='rb');
 
添加多个分区
alter table t_user_p add partition(nationality='rb') location 'hdfs://node-1:8020/user/hive/warehouse/nationality=rb' partition(nationality='hg') location 'hdfs://node-1:8020/user/hive/warehouse/nationality=hg';
load data local inpath '/export/data/hivedata/korea.txt' into table t_user_p partition(nationality='hg');
 
删除分区
alter table … drop if exists partition(xx=‘xx’)
alter table t_user_p drop if exists partition(nationality='rb');
 
修改分区
alter table t_user_p partition(nationality='hg') rename to partition(nationality='hanguo');
 
增加属性-表
alter table … set tblproperties(xx=‘xx’);
alter table table_name set tblproperties('属性'='属性值');
desc formatted table_name;
alter table t_user_p set tblproperties('EXTERNAL'='TRUE');--外
alter table table_name set tblproperties('EXTERNAL'='FALSE');--内
 
修改参数
alter table … change …
alter table t_flowcount change A changeA string;
 
Extension
https://www.cnblogs.com/sunfie/p/4375795.html
 
DML-插入表
Insert [overwrite | into] + select
多重插入数据
- mysql
 
--支持语法 效率极低 底层是通过MapReduce把数据写入到hive对应的那个位置下的。
create table t_a(id int, name string);
insert into table t_a values(1, "zhangsan");
-- mysql方式-插入表, 没有保证查询的顺序!
create table t_b(name string, id int);
insert into table t_b select * from t_a;
 
- hive
 
insert overwrite table t_b select name, id from t_a;
 
- 多重插入: 一次扫描多次插入 意义在于减少全表扫描的次数。
 
-- 普通插入
-- ps: 本质是两个sql语句、分别进行了全表的扫描查询。
insert into table t_c select id from t_a;
insert into table t_d select name from t_a;
-- 多重插入:
-- ps: 本质是一个sql语句,完成了一次扫描 两次插入
from t_a 
insert overwrite table t_c select id 
insert overwrite table t_d select name;
-- 检查
select * from t_c inner join t_d;
 
动态分区
静态分区
--静态分区(手动指定分区)
create table t_user_staic (id int, name string) partitioned by(country string)  row format delimited fields terminated by ',';
load data local inpath '/root/hivedata/static.txt' into table t_user_staic partition(country="china");
 
动态分区
- 在插入数据到表的时候 通过查询数据本身 根据查询的结果来确定分区值
 - 在使用动态分区之前 需要设置两个参数 一个是开启动态分区的功能 一个是指定动态分区的模式。
 
-- 动态分区 
-- 是否开启动态分区功能,默认false关闭。
set hive.exec.dynamic.partition=true;    
-- 动态分区的模式
-- strict(默认),表示必须指定至少一个分区为静态分区
-- nonstrict模式表示允许所有的分区字段都可以使用动态分区。
set hive.exec.dynamic.partition.mode=nonstrict;   
 
-- 创建
create table dynamic_partition_table(day string,ip string)row format delimited fields terminated by ",";
-- load
load data local inpath '/export/data/hivedata/date.txt' into table dynamic_partition_table;
+------------------------------+-----------------------------+--+
| dynamic_partition_table.day  | dynamic_partition_table.ip  |
+------------------------------+-----------------------------+--+
| 2015-05-10                   | ip1                         |
| 2015-05-10                   | ip2                         |
| 2015-06-14                   | ip3                         |
| 2015-06-14                   | ip4                         |
| 2015-06-15                   | ip1                         |
| 2015-06-15                   | ip2                         |
+------------------------------+-----------------------------+--+
-- 目标表
create table d_p_t(ip string) partitioned by (month string,day string);
-- 动态插入
insert overwrite table d_p_t partition (month, day) 
select ip,substr(day,1,7) as month, day from dynamic_partition_table;
+-----------------+--------------------+------------------+--+
| dynamic_par.ip  | dynamic_par.month  | dynamic_par.day  |
+-----------------+--------------------+------------------+--+
| ip1             | 2015-05            | 2015-05-10       |
| ip2             | 2015-05            | 2015-05-10       |
| ip3             | 2015-06            | 2015-06-14       |
| ip4             | 2015-06            | 2015-06-14       |
| ip1             | 2015-06            | 2015-06-15       |
| ip2             | 2015-06            | 2015-06-15       |
+-----------------+--------------------+------------------+--+
 
查询结果导出到文件系统
insert overwrite [local] directory … select …
- 导出到本地
 
insert overwrite local directory '/root/kylechong' select * from d_p_t where month='2015-05';
├── kylechong
│   └── 000000_0
 
- 导出到hdfs
 
insert overwrite directory '/zzz' select * from d_p_t where month="2015-06";
 
DML-Load
load data [local] inpath … into table …
-  
load加载数据
 
- 含义:加载装载数据操纵  也是hive官方推荐的加载数据的方式。
- 本质:将数据文件移到到hive表所对应的hdfs的位置下。  [复制 | 移到]
- 注意:在进行数据加载的过程中 不会对数据进行任何修改。 只是单纯的数据搬运移到过程。
 
-- 从linux本地文件系统复制上传数据
-- 本地加载: 本质就是对文件执行复制操作 [hadoop fs -put ...]
load data local inpath '/export/data/hivedata/1.txt' into table table_name;
-- 日志显示:Loading data to table kyle.table_name from file: /export/data/hivedata/1.txt
------------------------------------------------------------
-- 将hdfs的文件移动到hive表的位置路径下
-- hdfs加载: 本质就是对文件执行了移动操作 [hadoop fs -mv ...]
load data inpath '/zzz/1.txt' into table table_name;
--日志显示;Loading data to table kyle.table_name from hdfs://node-1:8020/zzz/1.txt
 
- 官方推荐
 
官方推荐使用load也好 自己使用hadoop fs命令也好。只要最终把数据填充到hvie表对应的那个位置目录下 ,就是成功的。当然某些操作例外,必须使用load命令。
 
DQL-查询表
select … from
cluster by(分且排序)
- 默认: 分桶查询
 
select * from t_stubuck cluster by sno;
---- 
默认:  mapreduce.job.reduces=-1
INFO  : Number of reduce tasks not specified. Defaulting to jobconf value of: 1
-----
 
- 设置: 分桶个数查询
 
set mapreduce.job.reduces=2;
select * from t_stubuck cluster by sno;
------
INFO  : Number of reduce tasks not specified. Defaulting to jobconf value of: 2
------
 
- distribute by + sort by = cluster by
 
select * from t_stubuck distribute by sno sort by sage;
 
Q: 分为几个部分?
用户不设置    mapreduce.job.reduces=-1  系统自动评估决定个数。
如果用户设置  set mapreduce.job.reduces=N; N为几就是几
 
Q: 如何分?
如果是数值字段   字段  % 分桶个数 
如果是其他字段   字段.hashcode 5 分桶个数
 
Q: 分桶查询和之前分桶表之间有啥关系?
-
 
Q: 分桶总的 hive.enforce.bucketing参数
set hive.enforce.bucketing = true
允许根据表自动选择正确数量的reducer,并按列自动选择集群。
--官方参考资料
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL+BucketedTables
 
order by [desc | asc]
-- 在编译期间reduce个数设置为1
select * from t_stubuck order by sage asc;
 
 
Q: 当手动设置reduce的个数之后 对order by全局排序是否有影响?
当sql中出现order by全局排序的时候  
意味着最终数据必须在一个文件中  
此时不管用户在环境中通过代码设置多少个reduce个数  
在编译期间 hive都会把它设置为1 保证全局。
 
Q: order by 和 sort by 的区别?
sort by 负责分桶内排序  先使用其他语法把数据进行分桶  sort by再针对每个分桶内进行排序
order by 负责全局排序  不会进行分桶操作 即时你设置了reduce个数  依然全局唯一输出。
 
 
inner join … on
- 表数据
 
--两张表数据如下 
+-------+---------+--+
| a.id  | a.name  |
+-------+---------+--+
| 1     | a       |
| 2     | b       |
| 3     | c       |
| 4     | d       |
| 7     | y       |
| 8     | u       |
+-------+---------+--+
+-------+---------+--+
| b.id  | b.name  |
+-------+---------+--+
| 2     | bb      |
| 3     | cc      |
| 7     | yy      |
| 9     | pp      |
+-------+---------+--+
 
- 内关联(只显示两边都满足join条件的结果)
 
select * from a inner join b on a.id=b.id;
-------等价----------
select * from a join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id  | a.name  | b.id  | b.name  |
+-------+---------+-------+---------+--+
| 2     | b       | 2     | bb      |
| 3     | c       | 3     | cc      |
| 7     | y       | 7     | yy      |
+-------+---------+-------+---------+--+
 
- 全外关联(除了不满足条件的 都显示)
 
select * from a full outer join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id  | a.name  | b.id  | b.name  |
+-------+---------+-------+---------+--+
| 2     | b       | 2     | bb      |
| 4     | d       | NULL  | NULL    |
| 8     | u       | NULL  | NULL    |
| 1     | a       | NULL  | NULL    |
| 3     | c       | 3     | cc      |
| 7     | y       | 7     | yy      |
| NULL  | NULL    | 9     | pp      |
+-------+---------+-------+---------+--+
 
- 左关联(以左表为准 右表与之关联 join上的显示 join不上的显示null)
 
select * from a left join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id  | a.name  | b.id  | b.name  |
+-------+---------+-------+---------+--+
| 1     | a       | NULL  | NULL    |
| 2     | b       | 2     | bb      |
| 3     | c       | 3     | cc      |
| 4     | d       | NULL  | NULL    |
| 7     | y       | 7     | yy      |
| 8     | u       | NULL  | NULL    |
+-------+---------+-------+---------+--+
select * from b left join a on a.id=b.id;
+-------+---------+-------+---------+--+
| b.id  | b.name  | a.id  | a.name  |
+-------+---------+-------+---------+--+
| 2     | bb      | 2     | b       |
| 3     | cc      | 3     | c       |
| 7     | yy      | 7     | y       |
| 9     | pp      | NULL  | NULL    |
+-------+---------+-------+---------+--+
 
- 右关联(以右表为准 左表与之关联 join上的显示 join不上的显示null)
 
select * from a right join b on a.id=b.id;
+-------+---------+-------+---------+--+
| a.id  | a.name  | b.id  | b.name  |
+-------+---------+-------+---------+--+
| 2     | b       | 2     | bb      |
| 3     | c       | 3     | cc      |
| 7     | y       | 7     | yy      |
| NULL  | NULL    | 9     | pp      |
+-------+---------+-------+---------+--+
select * from b right join a on a.id=b.id;
+-------+---------+-------+---------+--+
| b.id  | b.name  | a.id  | a.name  |
+-------+---------+-------+---------+--+
| NULL  | NULL    | 1     | a       |
| 2     | bb      | 2     | b       |
| 3     | cc      | 3     | c       |
| NULL  | NULL    | 4     | d       |
| 7     | yy      | 7     | y       |
| NULL  | NULL    | 8     | u       |
+-------+---------+-------+---------+--+
 
- 内关联(只显示左表的部分)
 
select * from b left semi join a on a.id=b.id;
select b.* from b join a on a.id=b.id;
+-------+---------+--+
| b.id  | b.name  |
+-------+---------+--+
| 2     | bb      |
| 3     | cc      |
| 7     | yy      |
+-------+---------+--+
 
- 级联问题计算(两个表笛卡尔积结果)慎用
 
select * from a corss join b;
本质上就是计算笛卡尔积
 
hive shell
/bin/hive
- 启动服务
 
-- 功能1:启动hive的各种服务 
/export/servers/hive/bin/hive --service metastore    #metastore元数据服务
/export/servers/hive/bin/hive --service hiveserver2  #hiveserver2第二代服务 配合beeline使用
 
- 一代客户端(可以直接连接metastore服务 访问hive)
 
PS: 因为有了beeline第二代客户端 bin/hive很多时间就充当启动服务的功能
/export/servers/hive/bin/hive
 
- 参数
 
-e sql片段
-f sql脚本
-- 执行语句
/export/servers/hive/bin/hive -e 'select * from kyletest.d_p_t'
-- 执行脚本
/export/servers/hive/bin/hive -f /root/hive.sql 
-----------
-- 在线上环境中  可以使用此方式加载sql文件执行 配合调度工具进行周期重复执行。
-- 在开发环境中 程序员需要保证所写sql 代码无误 能够正确实现业务需求  提交git svn。
 
hive 参数的配置方式
#方式1:安装包conf/hive-site.xml
#方式2:shell 命令行的时候 启动服务 --hiveconf  k=v
#方式3:set命令设置 比如:set mapreduce.job.reduces=2;
从范围来说:依次递减
	方式1:影响此安装包任何操作  全局
	方式2:启动进程  谁设置谁启动谁生效
	方式3:会话级别  谁链接服务 谁设置 谁生效
	
从优先级上说:set命令优先级最高的  覆盖之前的设置。
在实际开发中,最多使用的是set命令设置。 对其他用户的会话没有影响 且会话结束断开链接恢复默认。
谁开发谁设置谁生效。
 
-  
hive作为基于hadoop的数据仓库 在搭建hvie的时候指定了hadoop_home环境变量
因此hive也会把hadoop配置文件加载解析过来作为自己的一部分
 
查看命令
显示所有数据库show tables;
显示当前数据库所有表show databases |schemas;
显示表分区信息,不是分区表执行报错show partitions table_name;
显示当前版本 hive 支持的所有方法show functions;
查看表信息desc extended table_name;
查看表信息(格式化美观)desc formatted table_name;
查看数据库相关信息describe database database_name;
Hive执行任务终止
'前提':hive的sql大多数都是通过MapReduce程序来执行的。因此所谓的终止指的是终止mr程序。
 
-- 查看当前任务列表
hadoop job -list
--+------------------------------------------------------------------------------------------+-
Total jobs:1
 JobId 
 job_1590723919346_0006       
 http://node-1:8088/proxy/application_1590723919346_0006/
 --+------------------------------------------------------------------------------------------+-
 
 -- 杀死当前job
 hadoop job -kill job_1590723919346_0006 










