Hive
启动准备
-
启动hadoop
start-all.sh
-
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 :表明使用其他的类进行分隔符指定
[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: 还是需要放置在指定的位置?
/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中表的定义信息 结构化文件不会被删除的
一个表下面可以映射多个文件
要保证各个文件之间的结构:字段顺序、类型、个数和表定义的一致
如果不一致 能成功显示 不能成功显示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
overwrite: 覆盖
into: 修改
多重插入数据
--支持语法 效率极低 底层是通过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 …
- 含义:加载装载数据操纵 也是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 |
+-------+---------+-------+---------+--+
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 |
+-------+---------+-------+---------+--+
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