目录
hadoop离线day09--Apache Hive
今日内容大纲
1、HQL DDL 数据定义语言
分区表
分区表创建
分区表加载数据
总结及注意事项
多重分区表
分桶表
分桶表创建
分桶表加载数据
HQL DDL 数据定义语言
修改表
show场景语法
2、HQL DML 数据操纵语言
Dynamic partition inserts 动态分区插入
导出数据操作
3、HQL DQL 数据查询语言
Common Table Expressions(CTE)
Hive join
4、Hive shell命令行 参数配置
#1、HQL DDL 数据定义语言 创建表 分区表 分桶表 修改表 alter 常用的show命令 #2、HQL DML 数据操纵语言 load加载数据 insert插入数据 mysql:insert+values hive:insert+select 动态分区插入 数据导出 #3、HQL DQL 数据查询语言 select hive自己特有的查询 CTE语法 union语法 Hive join inner join、left join #4、Hive shell命令行 参数配置 bin/hive shell bin/beeline jdbc hive参数配置方式
分区表引入,产生背景
--创建一张表 映射一个文件 create table t_user(id int,name string,country string) row format delimited fields terminated by ','; --能否在一张表的目录下 映射多个文件呢? --可以 保证多个文件之间字段、类型、个数、顺序是一致 --查询:找出来自于中国的用户 select * from t_user where country ="china"; --问题:在where过滤的时候 需要进行全表扫描 判断过滤条件十分满足 --全表扫描性能不高 如何优化? --通过hdfs底层存储格式 猜想:能否基于文件去扫描指定的文件,而不是全表扫描 效率不就提高了吗?
--基于业务分析 决定根据国家分区 create table t_user_part(id int,name string,country string) partitioned by(country string) row format delimited fields terminated by ','; Error: Error while compiling statement: FAILED: SemanticException [Error 10035]: Column repeated in partitioning columns --建表报错 分区字段重复 create table t_user_part(id int,name string,country string) partitioned by(guojia string) row format delimited fields terminated by ',';
--猜想方式1:使用hadoop fs -put 上传表的目录下 失败 没有指定该文件属于哪个分区 没有指定分区值 --正确方式: load data语法 load data local inpath '/root/hivedata/chian.txt' into table t_user_part partition(guojia="zhongguo"); --加载china.txt文件到分区表中 并且指定该文件属于zhongguo分区。 load data local inpath '/root/hivedata/usa.txt' into table t_user_part partition(guojia="meiguo"); load data local inpath '/root/hivedata/japan.txt' into table t_user_part partition(guojia="riben");
分区表使用
--查询:找出来自于中国的用户 select * from t_user where country ="china"; --非分区字段查询 select * from t_user where guojia ="zhongguo"; --基于分区表分区字段查询
分区表是一种优化表,主要是提高查询效率,减少全表扫描。
分区的字段不能是表中已有的字段?为什么 分区字段也会作为结果显示查询内容上,不能重复。
分区字段是虚拟的字段,其内容不是来自于底层文件的映射,来自于加载数据时指定。
分区表底层形式就是在表的文件夹下面继续创建子文件,子文件的名字就是分区字段和分区值组合
#非分区表 /user/hive/warehouse/itcast.db/t_user china.txt japan.txt usa.txt #分区表 /user/hive/warehouse/itcast.db/t_user_part /guojia=zhongguo china.txt /guojia=riben japan.txt /guojia=meiguo usa.txt
企业中常见的分区字段
时间维度 年 月 天
地域维度 省 市
Hive支持在多个分区字段,也就是所谓多重分区表,常见的是2分区表。
多分区的意思是指在前一个分区的基础上继续分区
底层来看就是文件夹下面继续创建子文件
--创建2分区表 create table t_user_double_part(id int,name string,country string) partitioned by(guojia string,sheng string) row format delimited fields terminated by ','; --load load data local inpath '/root/hivedata/china_sh.txt' into table t_user_double_part partition(guojia="zhongguo",sheng="shanghai"); load data local inpath '/root/hivedata/china_bj.txt' into table t_user_double_part partition(guojia="zhongguo",sheng="beijing"); load data local inpath '/root/hivedata/usa_dz.txt' into table t_user_double_part partition(guojia="meiguo",sheng="dezhou"); --查询 select * from t_user_double_part where guojia ="zhongguo"; select * from t_user_double_part where guojia ="zhongguo" and sheng ="shanghai";
语法上剖析
[clustered by (col_name, col_name, ...) [sorted by (col_name [asc|desc], ...)] into num_buckets buckets] --精简 clustered by xxx into N buckets clustered by xxx 根据xxx分在一起 into N buckets 分为几桶 --通俗解释:根据xxx字段把表的数据分为N个部分。 t_user(id,name,country) 根据谁分? clustered by xxx xxx就是分的字段 分为几个部分?into N buckets N 如何分? --如果分桶的字段xxx是数值类型字段, xxx % N 余数相同的到一起 --如果分桶的字段xxx是字符串或者其他类型 xxx.hash % N 余数相同的到一起 --如果有需求 还可以知道每个分桶内排序规则 sorted by (col_name [asc|desc])
create table stu_buck(Sno int,Sname string,Sex string,Sage int,Sdept string) clustered by(Sno) into 4 buckets row format delimited fields terminated by ',';
--如何判断分桶表的数据加载成功 1、正确解析显示数据 2、底层文件分成N个部分 --直接hadoop fs-put 和load加载都是不可以的 --分桶表采用insert+select 间接的方式才能加载数据 --step1:创建一个普通的表 并加载数据到普通表中 create table student(Sno int,Sname string,Sex string,Sage int,Sdept string) row format delimited fields terminated by ','; --step2: 开启分桶功能 set hive.enforce.bucketing = true; --注意这个参数 hive.enforce.bucketing Default Value: Hive 0.x: false Hive 1.x: false Hive 2.x: removed, which effectively makes it always true (HIVE-12331) Added In: Hive 0.6.0 --step3: 把数据从普通表中查询出来插入到分桶表中 insert into table stu_buck select * from student;
分桶表使用
和正常表一样使用,底层查询时hive自动优化。
分桶表总结及注意事项
修改表的属性信息
修改表的分区属性信息
修改表的字段
语法核心关键字:alter
注意:在Hive中,修改表的操作使用不多,可以使用drop+create 替代。为什么?
#mysql中不这么干? create table--->insert values #意味着mysql加载数据的成本极高。 #hive中为什么可以? create table--->映射已经存在的文件(外部表保护文件) # 删除再创建的成本极低
栗子
--增加分区 先有分区文件 补充元数据 ALTER TABLE t_user_part ADD PARTITION (guojia='yingguo') location '/user/hive/warehouse/itcast.db/t_user_part/guojia=yingguo'; --删除分区 ALTER TABLE t_user_part DROP IF EXISTS PARTITION (guojia='yingguo'); --修改分区 重命名分区 ALTER TABLE t_user_part PARTITION (guojia='yingguo') RENAME TO PARTITION (guojia='dydg'); --列操作 ALTER TABLE table_name ADD|REPLACE COLUMNS (col_name STRING); --注:ADD 是代表新增一个字段,新增字段位置在所有列后面(partition 列前) --REPLACE 则是表示替换表中所有字段。 ALTER TABLE table_name RENAME TO new_table_name
--1、显示所有数据库 SCHEMAS和DATABASES的用法 功能一样 show databases; show schemas; --2、显示当前数据库所有表 show tables; SHOW TABLES [IN database_name]; --指定某个数据库 --3、显示表分区信息,分区按字母顺序列出,不是分区表执行该语句会报错 show partitions table_name; --4、显示表/分区的扩展信息 SHOW TABLE EXTENDED [IN|FROM database_name] LIKE table_name; show table extended like student; describe formatted itheima.student; --5、显示表的属性信息 show tblproperties student; --6、显示表建表语句 show create table student; --9、显示表中的所有列,包括分区列。 SHOW COLUMNS (FROM|IN) table_name [(FROM|IN) db_name]; show columns in student; --10、显示当前支持的所有自定义和内置的函数 show functions; --11、Describe desc --查看表信息 desc extended table_name; --查看表信息(格式化美观) desc formatted table_name; --查看数据库相关信息 describe database database_name;
#探究 1、hive做了什么 将结构化文件映射成为一张表 记录着映射信息(元数据) 2、MySQL中存储的是什么数据 存储着映射信息 元数据 3、HDFS中存储的是什么数据 存储的是结构化文件 表的真实的数据 #查看表的元数据信息 hive记录了这个表哪些信息 desc formatted student;
load
功能:加载操作是将数据文件移动到与 Hive表对应的位置的纯复制/移动操作。
语法
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 ...)]
核心关键字--local
有local 表示从本地文件系统加载到hive表中
没有local 表示从hdfs文件系统加载到hive表中
究竟哪个本地是本地文件系统。
栗子
create table student_from_local(Sno int,Sname string,Sex string,Sage int,Sdept string) row format delimited fields terminated by ','; create table student_from_hdfs(Sno int,Sname string,Sex string,Sage int,Sdept string) row format delimited fields terminated by ','; --1、从本地加载数据到student_from_local load data local inpath '/root/hivedata/students.txt' into table student_from_local; --从本地加载的时候 是一个数据复制操作 --底层的本质就是 hadoop fs -put --2、从HDFS加载数据到student_from_hdfs load data inpath '/stu/students.txt' into table student_from_hdfs; --从hdfs加载的时候 是一个数据移动操作 --底层的本质就是 hadoop fs -mv
结论:官方推荐使用load命令加载数据到Hive表中。实际上无论什么方式,只有把文件放置在表的目录下就可以。
insert插入数据
回顾
mysql: insert into table values(1,"zhangsan"); --insert +values语法在hive中能否使用。 create table t_insert(id int,name string); insert into table t_insert values(1,"allen"); --语法可以在hive使用 但是效率较低。 推荐使用load加载数据方式。
insert在hive中如何
语法:insert+select
功能:把后面查询返回的结果作为内容插入到表中 也是ETL中常见的操作。
注意:查询返回结果的字段类型、顺序、含义、个数要和待插入表一致。
栗子
create table t_insert_1(name string); insert into t_insert_1 select name from t_insert; --如何插入的表是分区表 还需要指定分区值 insert into t_insert_1 partition() select name from t_insert;
开启智能本地模式
SET hive.exec.mode.local.auto=true;
Multi Inserts 多重插入 多次插入
一次扫描,多次插入 减少全表扫描的次数
from source_table insert overwrite table test_insert1 select id insert overwrite table test_insert2 select name;
探讨
--动态分区、静态分区 --研究的是:分区表的分区值是如何决定的? load data local inpath '/root/hivedata/usa.txt' into table t_user_part partition(guojia="meiguo"); usa.txt--->meiguo --sql中写死的 静态分区 insert +seletc --根据查询结果动态确定的分区 动态分区
栗子
--step1: 开启动态分区功能 设定动态分区的执行模式 set hive.exec.dynamic.partition=true; #是否开启动态分区功能,默认false关闭。 set hive.exec.dynamic.partition.mode=nonstrict; #动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。 Error: Error while compiling statement: FAILED: SemanticException [Error 10096]: Dynamic partition strict mode requires at least one static partition column. To turn this off set hive.exec.dynamic.partition.mode=nonstrict (state=42000,code=10096) --理解严格 非严格模式 insert into table d_p_t partition(month="2015-05",day) select ip,day from dynamic_partition_table; --严格模式 insert into table d_p_t partition(month,day) --非严格模式 select ip,month,day from dynamic_partition_table; --step2:执行动态分区 insert overwrite table d_p_t partition (month,day) select ip,substr(day,1,7) as month,day from dynamic_partition_table;
语法
INSERT OVERWRITE [LOCAL] DIRECTORY directory1 SELECT ... FROM ...;
注意事项
local表示把数据导出到HS2所在机器的本地文件系统 否则就导出到HDFS.
OVERWRITE表示把目录下的数据给覆盖。
默认导出的数据以\001作为字段分隔符 也可以指定分隔符。
栗子
INSERT OVERWRITE LOCAL DIRECTORY '/tmp/aaa' SELECT * FROM student; INSERT OVERWRITE DIRECTORY '/aaa' SELECT * FROM student;
完整语法树
[WITH CommonTableExpression (, CommonTableExpression)*] SELECT [ALL | DISTINCT] select_expr, select_expr, ... FROM table_reference [WHERE where_condition] [GROUP BY col_list] [ORDER BY col_list] [CLUSTER BY col_list | [DISTRIBUTE BY col_list] [SORT BY col_list] ] [LIMIT [offset,] rows];
CLUSTER BY 分桶查询
功能:根据指定的字段把数据分成若干部分,每个部分中再根据这个字段进行排序,只能正序
概况:根据字段 分且排序动作。
0: jdbc:hive2://node1:10000> select * from student; +--------------+----------------+--------------+---------------+----------------+--+ | student.sno | student.sname | student.sex | student.sage | student.sdept | +--------------+----------------+--------------+---------------+----------------+--+ --1、根据谁分 CLUSTER BY xxx --2、分成几个部分 取决于底层reducetask的个数 个数如何决定的呢? 如果用户不设置 自己根据数据量大小自动评估 如果用户手动设置 就以设置的为准 --3、如何分 规则和分桶表的规则一模一样 select * from student cluster by sno; ---默认情况下 根据输入数据量来自动评估reducetask个数 Number of reduce tasks not specified. Estimated from input data size: 1 --手动设置reducetask个数 set mapreduce.job.reduces =2; Number of reduce tasks not specified. Defaulting to jobconf value of: 2 set mapreduce.job.reduces =3; Number of reduce tasks not specified. Defaulting to jobconf value of: 3 --需求:根据sno分为2个部分 每个部分中根据sage 倒序排序 set mapreduce.job.reduces =2; select * from student cluster by sno sort by sage desc; Error: Error while compiling statement: FAILED: SemanticException 1:45 Cannot have both CLUSTER BY and SORT BY clauses. Error encountered near token 'sage' (state=42000,code=40000)
DISTRIBUTE BY + SORT BY
功能:DISTRIBUTE BY 只负责分 SORT BY只负责排序 两个字段还可以不一样。
如果字段一样的话:CLUSTER BY(分且排序)= DISTRIBUTE BY(分) +SORT BY(排序)
set mapreduce.job.reduces =2; select * from student distribute by sno sort by sage desc;
ORDER BY 全局排序
如何理解全局二字? 全局意味着所有的数据都必须在一个文件中,意味着底层只能有一个reducetask.
为了满足order by全局的实现,在编译期间hive会强制将reducetask个数设置为1。
set mapreduce.job.reduces =4; select * from student order by sage desc; --在编译期间 hive把个数设置为1 用户设置的不生效 Number of reduce tasks determined at compile time: 1
union联合查询
功能:将多个select查询返回的结果集合并为一个结果集。
语法:
select_statement UNION [ALL | DISTINCT] select_statement UNION [ALL | DISTINCT] select_statement ...; --1、union= union distinct 结果集去重 --2、union all 结果集不去重
栗子
select sno,sname from student_from_local UNION select sno,sname from student_from_hdfs; --和上面一样 select sno,sname from student_from_local UNION DISTINCT select sno,sname from student_from_hdfs; --使用ALL关键字会保留重复行。 select sno,sname from student_from_local UNION ALL select sno,sname from student_from_hdfs limit 2;
注意事项
如果想针对某一条select结果进行条件控制 使用嵌套子查询包裹;
如果把条件控制写在最后一个select后,对整个union之后的结果集进行操作。
以with关键字引导的一个子查询 其命令可以在后续的查询中多次使用。
语法糖。
--select语句中的CTE with q1 as (select sno,sname,sage from student where sno = 95002) select * from q1; --嵌套子查询语法 select * from (select sno,sname,sage from student where sno = 95002) as q1; -- from风格 with q1 as (select sno,sname,sage from student where sno = 95002) from q1 select *; -- chaining CTEs 链式 with q1 as ( select * from student where sno = 95002), q2 as ( select sno,sname,sage from q1) select * from (select sno from q2) a;
产生背景
#现实中 不会把所有的数据都存储在一张表中 而是根据业务 应用分别存储。 #在某些查询的需求中 又需要基于多张表共同查询返回结果 需要join关联查询。
6种join语法
join_table: table_reference [INNER] JOIN table_factor [join_condition] | table_reference {LEFT|RIGHT|FULL} [OUTER] JOIN table_reference join_condition | table_reference LEFT SEMI JOIN table_reference join_condition | table_reference CROSS JOIN table_reference [join_condition] (as of Hive 0.10)
inner join
inner join == join 默认就是内连接 --左右两边都满足的返回
outer join
full outer join == outer join 全外连接 外连接
left join
以左表为准,显示左表的所有内容 右表与之关联 关联上的显示 关联不上的显示null
right join
与left join相反
left semi join
左半开连接 == 效果等于内关联只显示左表的部分 select * from a left semi join b on a.id = b.id; +-------+--------- | a.id | a.name +-------+--------- | 2 | b | 3 | c | 7 | y +-------+--------- select a.* from a inner join b on a.id=b.id; +-------+--------- | a.id | a.name +-------+--------- | 2 | b | 3 | c | 7 | y +-------+---------
cross join(#慎用)
--笛卡尔积join 交叉相差 往往不带on条件 --级联求和 级联累加 自己和自己join可以解决 --更好的方式 sum + windows function
注意事项
Hive 支持等值连接(a.id = b.id),不支持非等值(a.id>b.id)的连接。
select * from a join b on a.id = b.id; select * from a join b on a.id > b.id; --当下hive 2.1.0不支持。
难点
join的优化
map端join
reduce端join(common join)
bucket join
大小表join
大表join 空值处理问题
如何根据业务需求写join语句
shell命令行
位置:bin/hive
功能1:启动hive的相关服务
/export/server/hive/bin/hive --service hiveserver2|metastore
功能2:作为第一代客户端访问metastore服务
功能3:执行HQL脚本
#执行后面指定的sql /export/server/hive/bin/hive -e 'select sno from itcast.student limit 3' #执行后面指定的sql文件 vim xxx.sql $HIVE_HOME/bin/hive -f /home/my/hive-script.sql $HIVE_HOME/bin/hive -f hdfs://: /hive-script.sql #sql文件后缀名 见名知意 通常以.sql结尾 可以任意后缀名 保证里面内容sql语法正确即可。
Hive参数配置及方式
配置参数在哪里
https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties
如何配置参数
方式1:hive-site.xml中 覆盖default。
影响的是这个安装包的任何一种使用方式。 不管是启动服务 还是基于本安装包启动客户端 都会加载该文件。
方式2:--hiveconf
/export/server/hive/bin/hive --service metastore /export/server/hive/bin/hive --service metastore --hiveconf hive.root.logger=DEBUG,console 影响的服务的生命周期 客户端的生命周期
方式3:使用set命令
set hive.exec.dynamic.partition=true; #是否开启动态分区功能,默认false关闭。 set hive.exec.dynamic.partition.mode=nonstrict; 影响的客户端和服务之间的session会话 session结束 设置参数失效 恢复默认值
企业开发中,推荐使用set命令
谁需要 谁设置 谁生效 影响其他人使用。
优先级:set命令最高
Hive作为基于Hadoop的软件 还会把Hadoop的配置文件加载进来 作为自己的配置的一部分。