hive
- 1. hive 有哪些方式保存元数据,各有哪些特点?
- 2. hive内部表和外部表的区别
- 3.生产环境中为什么建议使用外部表?什么时候使用内部表?什么时候使用外部表?
- 4.你们数据库怎么导入hive 的,有没有出现问题
- 5.简述Hive中的虚拟列作用是什么,使用它的注意事项
- 扩展
- 6.hive partition分区
- 7. hive partition什么时候使用手动分区
- 8.hive partition怎么手动分区
- 9.hive partition什么时候使用自动分区
- 10.hive partition怎么自动分区
- 11.如何查看分区
- 12.分桶结构表clustered
- 13.分桶表怎么构建
- 14.分区表和分桶表的区别
- 分区表
- 分桶表
- 15.insert into 和 insert overwrite区别?
- 16.假如一个分区的数据主部错误怎么通过hivesql删除hdfs
- 17.Hive 表关联查询,如何解决数据倾斜的问题?
- 1)倾斜原因:
- 2)解决⽅案
- 18.请谈⼀下 Hive 的特点,Hive 和 RDBMS 有什么异同?(重新整理)
- 19.请说明 hive 中 Sort By,Order By,Cluster By,Distrbute By 各代表什么意思?
- 20.简要描述数据库中的 null,说出 null 在 hive 底层如何存储,并 解释 select a.* from t1 a left outer join t2 b on a.id=b.id where b.id is null; 语句的含义?
- 21.写出 hive 中 split、coalesce 及 collect_list 函数的⽤法(可举 例)?
- 22.Hive 有哪些⽅式保存元数据,各有哪些特点?
- 23.Hive 内部表和外部表的区别?
- 24.Hive 的 HSQL 转换为 MapReduce 的过程?(重新整理)
- 25.Hive 底层与数据库交互原理?
- 26.请把下⾯语句⽤ Hive 实现
- 27.写出将 text.txt ⽂件放⼊ hive 中 test 表‘2016-10-10’ 分区 的语句,test 的分区字段是 l_date
- 28.Hive 如何进⾏权限控制?
- 29.对于 hive,你写过哪些 udf 函数,作⽤是什么?
- 开发过程
- 30.Hive 中的压缩格式 TextFile、SequenceFile、RCfile 、ORCfile 各有什么区别?
- 31.Hive join 过程中⼤表⼩表的放置顺序?
- 32.Hive 的两张表关联,使⽤ MapReduce 怎么实现?
- 33.Hive 中使⽤什么代替 in 查询?
- 34.所有的 Hive 任务都会有 MapReduce 的执⾏吗?
- 35.Hive 的函数:UDF、UDAF、UDTF 的区别?
- 36.说说对 Hive 桶表的理解?
- 37.Hive ⾃定义 UDF 函数的流程?
- 38.Hive 可以像关系型数据库那样建⽴多个库吗?
- 39.Hive 实现统计的查询语句是什么?
- 40.Hive 优化措施
- 1.Fetch 抓取
- 2.本地模式
- 3.表的优化
- 优化措施4.数据倾斜
- 优化措施5.`并⾏执⾏`
- 优化措施6.`严格模式`
- 优化措施7.`JVM 重⽤`
- 化措施8.`推测执⾏`
- 优化措施9.`压缩`
- 优化措施10.EXPLAIN(执⾏计划)
- 41.Hive 数据分析⾯试题
- 1 情景题:分组 TOPN
- 2 情景题:where 与 having
- 3 情景题:数据倾斜
- 4 情景题:分区表
- 42.hive导入导出
- 导入
- 导出
- 43.Hive的存储格式及压缩算法
- 存储格式
- 压缩算法
- 44.Hive中小文件问题
- 产生:
- 影响
- 解决
- map/reduce端的相关参数的设置
- 配置Hive结果合并
- 45.Hive中Join的类型和用法
- 概览:
- left semi join和left join区别
- 实例
- 46.Hive严格模式
- 47.sparkSQL一定比hive快吗,能否想出一种场景,sparkSQL比hive慢(重点)
- sparkSQL之所以快
1. hive 有哪些方式保存元数据,各有哪些特点?
- 解答:
- 1、默认的存储位置:
内存数据库derby,安装小,但是数据存在内存,不稳定
- 2、
mysql数据库
,数据存储模式可以自己设置,持久化好
,查看方便。
2. hive内部表和外部表的区别
- 解答:
主要体现在删除时
- 内部表:加载数据到hive所在的hdfs目录
- 元数据中表的信息会被删除,HDFS中表的目录以及数据也会被删除
- 适用于中间表、结果表(数据恢复起来比较快的)
- 外部表(external关键字):不加载数据到hive所在的hdfs目录
- 元数据中表的信息会被删除,但是HDFS中表的目录以及数据依旧存在
- 只是删除了HDFS与Hive的表的关联
-
适合应用于多张表共用一份数据的情况下
,即共享源数据的时候
3.生产环境中为什么建议使用外部表?什么时候使用内部表?什么时候使用外部表?
- 解答:
- 1、因为
外部表不会加载数据到hive
,减少数据传输、数据还能共享
。 - 2、hive不会修改数据,所以无需担心数据的损坏
- 3、删除表时,只删除表结构、不删除数据。
- 4、ods层的埋点日志和业务抽取数据可以使用
外部表
,因为被误删除恢复会比较麻烦(实时采集) - 5、抽取过来处理后的数据恢复起来很快,建议使用
内部表
(中间表&结果表)
4.你们数据库怎么导入hive 的,有没有出现问题
- 解答:
- 在导入hive的时候,如果数据库中有blob或者text字段,会报错。有个参数limit
5.简述Hive中的虚拟列作用是什么,使用它的注意事项
- 解答:
- 解释:
此列在表中并未真正存在
- Hive提供了三个虚拟列:
- INPUT__FILE__NAME
- 每一个map任务对应 输入文件的目录及文件名
- BLOCK__OFFSET__INSIDE__FILE
- 当前map任务处理的数据所对应的偏移量,文件中的
块内偏移量
- ROW__OFFSET__INSIDE__BLOCK
- 默认不开启,需要设置参数,
文件的行偏移量
- 但ROW__OFFSET__INSIDE__BLOCK默认是不可用的,需要设置hive.exec.rowoffset为true才可以。- 可以用来排查有问题的输入数据。
- INPUT__FILE__NAME,
mapper任务的输出文件名
。 - BLOCK__OFFSET__INSIDE__FILE,
当前全局文件的偏移量
。对于块压缩文件,就是当前块的文件偏移量,即当前块的第一个字节在文件中的偏移量。
hive> SELECT INPUT__FILE__NAME, BLOCK__OFFSET__INSIDE__FILE, line
> FROM hive_text WHERE line LIKE '%hive%' LIMIT 2;
har://file/user/hive/warehouse/hive_text/folder=docs/
data.har/user/hive/warehouse/hive_text/folder=docs/README.txt 2243
har://file/user/hive/warehouse/hive_text/folder=docs/
data.har/user/hive/warehouse/hive_text/folder=docs/README.txt 3646
扩展
- 文件的行偏移量平时作用不大,但这三个参数在找错误方面很有用
- 已知clickcube_mid表中有一个字段 regioncode , regioncode 描述了 一个ip对应的region信息,这个regioncode 目前使用的是原始值,为日志中直接获取。
- 某一天,由于regioncode 异常,导致spark 进程中断,查找得知是 regioncode 不合理导致,此时我们需要找到错误的regioncode, 可以进行如下的查询:
SELECT
INPUT__FILE__NAME,
BLOCK__OFFSET__INSIDE__FILE,
ROW__OFFSET__INSIDE__BLOCK,
substr(regioncode,0,20)
FROM clickcube_mid
WHERE length(regioncode) > 100;
6.hive partition分区
- 功能:将数据按照数据本身分区的规则来存储
- 本质:实现了底层程序的输入的优化
- 通过分区,先对分区过滤,然后再作为输入
- 比先读取所有数据,再过滤,性能要高的多
- 不做分区表:表的最后一级目录就是表的目录
- 做了分区表:表的最后一级目录是分区的目录
- 分区的方式:
- 手动分区
- 自动分区
7. hive partition什么时候使用手动分区
- 如果
数据文件是已经按照分区分好的每个文件,就用手动分区
- 每天一个文件
- 每个部门一个文件
8.hive partition怎么手动分区
- step1:创建分区表
create table tb_emp_part1(
empno string,
ename string,
job string,
managerno string,
hiredate string,
salary double,
jiangjin double,
deptno string
)
partitioned by (department int)
row format delimited fields terminated by '\t';
- setp2:加载数据
load data local inpath '/export/datas/emp10.txt' into table tb_emp_part1 partition(department = 10);
load data local inpath '/export/datas/emp20.txt' into table tb_emp_part1 partition(department = 20);
load data local inpath '/export/datas/emp30.txt' into table tb_emp_part1 partition(department = 30);
9.hive partition什么时候使用自动分区
- 如果数据是一个整体,没有按照分区规则变成多个文件
10.hive partition怎么自动分区
- step1:先创建一个张原始数据表,放所有数据:tb_emp
- step2:将所有数据通过程序来实现分区,写入新的分区表
- step3:开启自动分区
- set hive.exec.dynamic.partition.mode=nonstrict;
- step4:创建分区表
create table tb_emp_part2(
empno string,
ename string,
job string,
managerno string,
hiredate string,
salary double,
jiangjin double
)
partitioned by (dept string)
row format delimited fields terminated by '\t';
- step5:从原始数据表加载到分区表
insert into table tb_emp_part2 partition(dept)
select * from tb_emp;
- 实现:判断tb_emp中的部门编号:deptno有哪几种值,第一种值作为第一个分区,第二种值作为第二个分区,将对应的数据放入对应的分区
- 如何知道我是按照tb_emp中的deptno做的分区?
- 按照查询语句的最后一个字段做分区,写入新表
- 如果分区的字段不是最后一个字段怎么办?
- 例如:
我想按照job进行分区,那么select的时候将其放到最后
create table tb_emp_part2(
empno string,
ename string,
managerno string,
hiredate string,
salary double,
jiangjin double,
deptno string
)
partitioned by (job string)
row format delimited fields terminated by '\t';
insert into table tb_emp_part2 partition(job)
select
empno,ename,managerno,hiredate
,salary,jiangjin,deptno
,job
from tb_emp;
11.如何查看分区
show partitions 表名;
12.分桶结构表clustered
- 本质:
就是底层MapReduce的分区,分桶的规则按照分桶字段的HASH取余
- 应用场景:
- SMB Join:适合于
大表 join 大表
的应用场景,是一种优化以后 join
- sort merge bulket join
- 如果两张表要进行SMB Join,要求两张表必须都为桶表
- Reduce join:适合于`大表join大表,但是比较慢
- A表:1亿条
- B表:1亿条
- reducejoin时:A表的每一条都需要与B表的每一条进行比较,然后关联
比较过程类似于笛卡尔积
13.分桶表怎么构建
- 注意:
分桶的数据是不能直接load进去的,必须通过MapReduce进行分区处理才能分桶
- step1:开启分桶
set hive.enforce.bucketing=true;
- step2:创建分桶表
create table tb_emp_bucket(
empno string,
ename string,
job string,
managerno string,
hiredate string,
salary double,
jiangjin double,
deptno string
)
clustered by (deptno) into 3 BUCKETS
row format delimited fields terminated by '\t';
- step3:从原始数据表加载到分桶表
insert overwrite table tb_emp_bucket
select * from tb_emp cluster by (deptno);
14.分区表和分桶表的区别
- 共同点:大数据的处理思想:
大而化小,分而治之
- 字段:分区的字段是假的,分桶的字段是真的
- 目录:
分区是目录级别,分桶是文件级别
- 目的:
-
分区
是为了加快输入
的性能,会构建元数据,表的最后一级目录是分区的目录 -
分桶
是为了SMB Join
而构建的,表到最后一级目录还是表的目录
分区表
- 本质减少mr的工作量,比如我们要查询某一字段的全部数据,可以只对目录下的分区文件进行一个mr作业就可以了
- 对数据进行水平切分,每个分区即为一个物理文件夹。
- 按照某列或某些列分为多个分区,容易数据倾斜
- 物理表现为:目录到分区,对应不同文件夹
- 分区字段为
假
- 应用场景:比如国家,时间
分桶表
- 本质减少shuffle花费的时间,表文件会被物理分桶为不同的文件,被分桶的数据被统一放到了一个或几个切片,这样可以让相同分桶的字段join,只需要把这两个分桶shuffer到一个reducer中就可以了
- 对数据进行垂直切分,每个分桶即为一个文件。
- 按照某列hash值%桶个数分割
- 物理表现为:目录到表,对应不同文件,细粒度
- 分区字段为真
- 应用场景:比如班级,某些有固定规定的字段
15.insert into 和 insert overwrite区别?
- 解答:
- insert into:
- 将某一张表中的数据写到另一张表中
- insert overwrite:
- 覆盖之前的内容。
- 如果有分区,只会重写当前分区数据
16.假如一个分区的数据主部错误怎么通过hivesql删除hdfs
- 解答:
alter table ptable drop partition (daytime='20140911',city='bj');
- 元数据,数据文件都删除,但目录daytime= 20140911还在
17.Hive 表关联查询,如何解决数据倾斜的问题?
- 可以参考
1)倾斜原因:
- map 输出数据按 key Hash 的分配到 reduce 中,由于 key 分布不均匀、业务数据本身的特、 建表时考虑不周、等原因
造成的 reduce 上的数据量差异过⼤
。
- (1)key 分布不均匀;
- (2)业务数据本身的特性;
- (3)建表时考虑不周;
- (4)某些 SQL 语句本身就有数据倾斜;
- 如何避免:对于 key 为空产⽣的数据倾斜,可以对其赋予⼀个随机值
2)解决⽅案
- (1)参数调节:
- hive.map.aggr = true
- hive.groupby.skewindata=true
- 有数据倾斜的时候进⾏负载均衡,当选项设定位 true,⽣成的查询计划会有两个
MR Job
。 第⼀个 MR Job 中,Map 的输出结果集合会随机分布
到 Reduce 中,每个 Reduce 做部分聚合 操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从⽽达到负载均衡的⽬的;第⼆个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同⼀个 Reduce 中), 最后完成最终的聚合操作
。 - (2)SQL 语句调节:
- ① 选⽤ join key 分布最均匀的表作为驱动表。做好列裁剪和 filter 操作,以达到两表做 join 的时候,数据量相对变⼩的效果。
- ② ⼤⼩表 Join: 使⽤ map join 让⼩的维度表(1000 条以下的记录条数)先进内存。在 map 端完成 reduce.
- ③⼤表 Join ⼤表:
把空值的 key 变成⼀个字符串加上随机数,把倾斜的数据分到不同的 reduce 上,由于 null 值关联不上,处理后并不影响最终结果
。 - ④ count distinct ⼤量相同特殊值: count distinct 时,将值为空的情况单独处理,如果是计算 count distinct,可以不⽤处理, 直接过滤,在最后结果中加 1。如果还有其他计算,需要进⾏ group by,可以先将值为空的 记录单独处理,再和其他计算结果进⾏ union。
18.请谈⼀下 Hive 的特点,Hive 和 RDBMS 有什么异同?(重新整理)
- hive 是基于 Hadoop 的⼀个
数据仓库
⼯具,可以将结构化的数据⽂件映射为⼀张数据库 表,并提供完整的 sql 查询功能,可以将 sql 语句转换为 MapReduce 任务进⾏运⾏
。
- 其优点 是学习成本低,
可以通过类 SQL 语句快速实现简单的 MapReduce 统计
,不必开发专⻔的 MapReduce 应⽤,⼗分适合数据仓库的统计分析,但是 Hive 不⽀持实时查询。
- Hive 与关系型数据库的区别:
19.请说明 hive 中 Sort By,Order By,Cluster By,Distrbute By 各代表什么意思?
- order by:会对输⼊做
全局排序
,因此只有⼀个 reduce(r 多个 reducer ⽆法保证全局有序)。 只有⼀个 reducer,会导致当输⼊规模较⼤时,需要较⻓的计算时间。 - sort by:分区内排序,
不是全局排序,其在数据进⼊ reducer 前完成排序
,每个reduce内有序。 - distribute by:
按照指定的字段对数据进⾏划分输出到不同的 reduce 中,一般结合sort by
,类似MR中Partition,按照指定的key进行分区。 - cluster by:
除了具有 distribute by 的功能外还兼具 sort by 的功能
,指定的列只能是降序
,不能指定asc和desc。
20.简要描述数据库中的 null,说出 null 在 hive 底层如何存储,并 解释 select a.* from t1 a left outer join t2 b on a.id=b.id where b.id is null; 语句的含义?
-
null 与任何值运算的结果都是 null
, 可以使⽤ is null、is not null 函数指定在其值为 null 情况下的取值。 - null 在 hive 底 层 默 认 是 ⽤
'\N'
来 存 储 的 , 可 以 通 过 alter table test SET SERDEPROPERTIES(‘serialization.null.format’ = ‘a’);来修改。 查询出 ID在t1表存在在t2不存在的数据
21.写出 hive 中 split、coalesce 及 collect_list 函数的⽤法(可举 例)?
- split 将字符串转化为数组,即:split(‘a,b,c,d’ , ‘,’) ==> [“a”,“b”,“c”,“d”]。
- coalesce(T v1, T v2, …) 返回参数中的第⼀个⾮空值;如果所有值都为 NULL,那么返 回 NULL。
-
collect_list 列出该字段所有的值,不去重
select collect_list(id) from table。
22.Hive 有哪些⽅式保存元数据,各有哪些特点?
- Hive ⽀持三种不同的元存储服务器,分别为:
内嵌式元存储服务器、本地元存储服务器、 远程元存储服务器
,每种存储⽅式使⽤不同的配置参数。 - 内嵌式元存储主要⽤于单元测试,在该模式下每次只有⼀个进程可以连接到元存储, Derby 是内嵌式元存储的默认数据库。
- 在本地模式下,每个 Hive 客户端都会打开到数据存储的连接并在该连接上请求 SQL 查 询。
- 在远程模式下,所有的 Hive 客户端都将打开⼀个到元数据服务器的连接,该服务器依 次查询元数据,元数据服务器和客户端之间使⽤ Thrift 协议通信。
23.Hive 内部表和外部表的区别?
- 创建表时:
- 创建
内部表
时,会将数据移动到数据仓库指向的路径
; - 若创建
外部表
,仅记 录数据所在的路径, 不对数据的位置做任何改变
。
- 删除表时:
- 在删除表的时候,
内部表的元数据和数据会被⼀起删除
, - ⽽
外部表只删除元 数据,不删除数据
。 - 这样
外部表相对来说更加安全些,数据组织也更加灵活,⽅便共享源数 据
。
24.Hive 的 HSQL 转换为 MapReduce 的过程?(重新整理)
HiveSQL ->AST(抽象语法树) -> QB(查询块) ->OperatorTree(操作树)->优化后的操作 树->mapreduce 任务树->优化后的 mapreduce 任务树
- 过程描述如下:
- SQL Parser:Antlr 定义 SQL 的语法规则,完成 SQL 词法,语法解析,将 SQL 转化为抽 象 语法树 AST Tree;
- Semantic Analyzer:遍历 AST Tree,抽象出查询的基本组成单元 QueryBlock;
- Logical plan:遍历 QueryBlock,翻译为执⾏操作树 OperatorTree; Logical plan optimizer: 逻 辑 层 优 化 器 进 ⾏ OperatorTree 变 换 ,合 并 不 必 要 的 ReduceSinkOperator,减少 shuffle 数据量;
- Physical plan:遍历 OperatorTree,翻译为 MapReduce 任务;
- Logical plan optimizer:物理层优化器进⾏ MapReduce 任务的变换,⽣成最终的执⾏计 划;
25.Hive 底层与数据库交互原理?
- 由于 Hive 的元数据可能要⾯临不断地更新、修改和读取操作,所以它显然不适合使⽤ Hadoop ⽂件系统进⾏存储。⽬前
Hive 将元数据存储在 RDBMS
中,⽐如存储在 MySQL、 Derby 中。元数据信息包括:存在的表、表的列、权限和更多的其他信息
。
26.请把下⾯语句⽤ Hive 实现
select a.key,a.value
from a where a.key not exists (select b.key from b)
27.写出将 text.txt ⽂件放⼊ hive 中 test 表‘2016-10-10’ 分区 的语句,test 的分区字段是 l_date
LOAD DATA LOCAL INPATH '/your/path/test.txt'
OVERWRITE INTO TABLE test PARTITION (l_date='2016-10-10')
28.Hive 如何进⾏权限控制?
- ⽬前 hive ⽀持简单的权限管理,默认情况下是不开启,这样所有的⽤户都具有相同的权 限,同时也是超级管理员,也就对 hive 中的所有表都有查看和改动的权利,这样是不符合 ⼀般数据仓库的安全原则的。Hive 可以是基于元数据的权限管理,也可以基于⽂件存储级 别的权限管理。
- 为了使⽤ Hive 的授权机制,有两个参数必须在 hive-site.xml 中设置:
<property>
<name>hive.security.authorization.enabled</name>
<value>true</value>
<description>enable or disable the hive client authorization</description>
</property>
<property>
<name>hive.security.authorization.createtable.owner.grants</name>
<value>ALL</value>
<description>the privileges automatically granted to the owner whenever a table gets created.
An example like "select,drop" will grant select and drop privilege to the owner of the
table</description>
</property>
- Hive ⽀持以下权限:
- Hive 授权的核⼼就是⽤户(user)、组(group)、⻆⾊(role)。
- Hive 中的⻆⾊和平常我们认知的⻆⾊是有区别的,Hive 中的⻆⾊可以理解为⼀部分有 ⼀些相同“属性”的⽤户或组或⻆⾊的集合。这⾥有个递归的概念,就是⼀个⻆⾊可以是⼀些⻆⾊的集合。
- 下⾯举例进⾏说明:
⽤户 组
张三 G_db1
李四 G_db2
王五 G_bothdb
- 如上有三个⽤户分别属于 G_db1、G_db2、G_alldb。G_db1、G_db2、G_ bothdb 分别表示该组⽤户可以访问数据库 1、数据库 2和可以访问 1、2两个数据库。现在可以创建 role_db1和 role_db2,分别并授予访问数据库 1和数据库 2的权限。这样只要将 role_eb1赋给 G_db1(或者该组的所有⽤户),将 role_eb2赋给 G_db2,就可以是实现指定⽤户访问指定数据库。最后创建role_bothdb 指向 role_db1、role_db2(role_bothdb 不需要指定访问那个数据库),然后 role_bothdb 授予 G_bothdb,则 G_bothdb 中的⽤户可以访问两个数据库。
- Hive 的⽤户和组使⽤的是 Linux 机器上的⽤户和组,⽽⻆⾊必须⾃⼰创建。
⻆⾊管理:
--创建和删除⻆⾊
create role role_name;
drop role role_name;
--展示所有 roles
show roles
--赋予⻆⾊权限
grant select on database db_name to role role_name;
grant select on [table] t_name to role role_name;
--查看⻆⾊权限
show grant role role_name on database db_name;
show grant role role_name on [table] t_name;
--⻆⾊赋予⽤户
grant role role_name to user user_name
--回收⻆⾊权限
revoke select on database db_name from role role_name;
revoke select on [table] t_name from role role_name;
--查看某个⽤户所有⻆⾊
show role grant user user_name;
29.对于 hive,你写过哪些 udf 函数,作⽤是什么?
- ⽇期处理 UDF 函数。
开发过程
- 1-开发udf程序:
继承UDF类,实现一个或者多个evaluate方法
- 2-打成jar包
- 3-上传jar包到集群中,并添加到hive的环境变量中,在hive中执行
add jar /export/datas/udf.jar;
- 4-创建临时函数:
create temporary function transDate as 'bigdata.hanjiaxiaozhi.cn.hive.udf.UserUDF';
- 5-测试函数:
select transDate("18/Aug/2019:12:30:05");
- 6-删除临时函数
DROP TEMPORARY FUNCTION transDate;
30.Hive 中的压缩格式 TextFile、SequenceFile、RCfile 、ORCfile 各有什么区别?
- TextFile
- 默认格式,存储⽅式为⾏存储,数据不做压缩,磁盘开销⼤,数据解析开销⼤。 可结合Gzip、Bzip2使⽤(系统⾃动检查,执⾏查询时⾃动解压),但使⽤这种⽅式,压缩后的⽂件不⽀持 split,Hive 不会对数据进⾏切分,从⽽⽆法对数据进⾏并⾏操作。并且在反序列化过程中,必须逐个字符判断是不是分隔符和⾏结束符,因此反序列化开销会⽐ SequenceFile ⾼⼏⼗倍。
- SequenceFile
- SequenceFile 是 Hadoop API 提供的⼀种⼆进制⽂件⽀持,,存储⽅式为⾏存储,其具有使⽤⽅便、可分割、可压缩的特点。
- SequenceFile ⽀持三种压缩选择:NONE,RECORD,BLOCK。Record 压缩率低,⼀般建议使⽤ BLOCK 压缩。
- 优势是⽂件和 hadoop api 中的 MapFile 是相互兼容的
- RCFile
- 存储⽅式:数据按⾏分块,每块按列存储。结合了⾏存储和列存储的优点:
- ⾸先,RCFile 保证同⼀⾏的数据位于同⼀节点,因此元组重构的开销很低;
- 其次,像列存储⼀样,RCFile 能够利⽤列维度的数据压缩,并且能跳过不必要的列读取;
- RCFile 的⼀个⾏组包括三个部分:
- 第⼀部分是⾏组头部的【同步标识】,主要⽤于分隔 hdfs 块中的两个连续⾏组
- 第⼆部分是⾏组的【元数据头部】,⽤于存储⾏组单元的信息,包括⾏组中的记录数、每个列的字节数、列中每个域的字节数
- 第三部分是【表格数据段】,即实际的列存储数据。在该部分中,同⼀列的所有域顺序存储。
- 从图可以看出,⾸先存储了列 A 的所有域,然后存储列 B 的所有域等。
- 数据追加:RCFile 不⽀持任意⽅式的数据写操作,仅提供⼀种追加接⼝,这是因为底层的 HDFS 当前仅仅⽀持数据追加写⽂件尾部。
- ⾏组⼤⼩:⾏组变⼤有助于提⾼数据压缩的效率,但是可能会损害数据的读取性能,因为这样增加了 Lazy 解压性能的消耗。⽽且⾏组变⼤会占⽤更多的内存,这会影响并发执⾏的其他 MR 作业。考虑到存储空间和查询效率两个⽅⾯,Facebook 选择 4MB 作为默认的⾏组⼤⼩,当然也允许⽤户⾃⾏选择参数进⾏配置。
- ORCFile
- 存储⽅式:数据按⾏分块 每块按照列存储。
- 压缩快 快速列存取。
- 效率⽐ rcfile ⾼,是 rcfile 的改良版本。
- 以下为 RCFile、TextFile、SequenceFile 三种⽂件的存储情况:
[hadoop@master ~]$ hadoop dfs -dus /user/Hive/warehouse/*
hdfs://master :9000/user/Hive/warehouse/hbase_table_1 0
hdfs://master :9000/user/Hive/warehouse/hbase_table_2 0
hdfs://master :9000/user/Hive/warehouse/orcfile_table 0
hdfs://master :9000/user/Hive/warehouse/rcfile_table 102638073
hdfs://master :9000/user/Hive/warehouse/seqfile_table 112497695
hdfs://master :9000/user/Hive/warehouse/testfile_table 536799616
hdfs://master :9000/user/Hive/warehouse/textfile_table 107308067
[hadoop@singlehadoop ~]$ hadoop dfs -ls /user/Hive/warehouse/*/
-rw-r--r-- 2 hadoop supergroup 51328177 2014-03-20 00:42
/user/Hive/warehouse/rcfile_table/000000_0
-rw-r--r-- 2 hadoop supergroup 51309896 2014-03-20 00:43
/user/Hive/warehouse/rcfile_table/000001_0
-rw-r--r-- 2 hadoop supergroup 56263711 2014-03-20 01:20
/user/Hive/warehouse/seqfile_table/000000_0
-rw-r--r-- 2 hadoop supergroup 56233984 2014-03-20 01:21
/user/Hive/warehouse/seqfile_table/000001_0
-rw-r--r-- 2 hadoop supergroup 536799616 2014-03-19 23:15
/user/Hive/warehouse/testfile_table/weibo.txt
-rw-r--r-- 2 hadoop supergroup 53659758 2014-03-19 23:24
/user/Hive/warehouse/textfile_table/000000_0.gz
-rw-r--r-- 2 hadoop supergroup 53648309 2014-03-19 23:26
/user/Hive/warehouse/textfile_table/000001_1.gz
- 总结:(重要)
- 相⽐ TEXTFILE 和 SEQUENCEFILE,RCFILE 由于列式存储⽅式,数据加载时性能消耗较⼤,但是具有较好的压缩⽐和查询响应。
- 数据仓库的特点是⼀次写⼊、多次读取,因此,整体来看,RCFILE 相⽐其余两种格式具有较明显的优势。
31.Hive join 过程中⼤表⼩表的放置顺序?
- 解答:
- 个人感觉这个解释不太满意,不过小表放前,养成习惯也好
- 1.将最⼤的表放置在 JOIN 语句的最右边,或者直接使⽤/*+ streamtable(table_name) */指出。
- 2.在编写带有 join 操作的代码语句时,应该
将条⽬少的表/⼦查询放在 Join 操作符的左边
。因为在 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,载⼊条⽬较少的表可以有效减少 OOM(out of memory)即内存溢出。所以对于同⼀个 key 来说,对应的 value 值⼩的放前,⼤的放后,这便是“⼩表放前”原则。若⼀条语句中有多个 Join,依据Join 的条件相同与否,有不同的处理⽅法。
32.Hive 的两张表关联,使⽤ MapReduce 怎么实现?
- 解答:
- 如果其中有⼀张表为⼩表,直接使⽤ map 端 join 的⽅式(map 端加载⼩表)进⾏聚合。
- 如果两张都是⼤表,那么采⽤联合 key,联合 key 的第⼀个组成部分是 join on 中的公共字段,第⼆部分是⼀个 flag,0 代表表 A,1 代表表 B,由此让 Reduce 区分客户信息和订单信息;在 Mapper 中同时处理两张表的信息,将 join on 公共字段相同的数据划分到同⼀个分区中,进⽽传递到⼀个 Reduce 中,然后在 Reduce 中实现聚合。
33.Hive 中使⽤什么代替 in 查询?
- 解答:
- 在 Hive 0.13 版本之前,通过 left outer join 实现 SQL 中的 in 查询
- 0.13 版本之后,Hive已经⽀持 in 查询。
34.所有的 Hive 任务都会有 MapReduce 的执⾏吗?
- 解答:
- 不是,从 Hive0.10.0 版本开始
- 对于简单的不需要聚合的类似
SELECT <col> from <table>LIMIT n
语句,不需要起 MapReduce job,直接通过Fetch task
获取数据。
35.Hive 的函数:UDF、UDAF、UDTF 的区别?
- 解答:
-
UDF
: 单⾏进⼊,单⾏输出 →一对一
-
UDAF
: 多⾏进⼊,单⾏输出 →多对一
-
UDTF
: 单⾏输⼊,多⾏输出 →一对多
36.说说对 Hive 桶表的理解?
- 解答:
- 桶表是
对数据进⾏哈希取值,然后放到不同⽂件中存储
。 - 数据加载到桶表时,会
对字段取 hash 值,然后与桶的数量取模
。把数据放到对应的⽂件中。物理上,每个桶就是表(或分区⽬录⾥的⼀个⽂件,⼀个作业产⽣的桶(输出⽂件)和reduce 任务个数相同。 - 桶表专⻔⽤于抽样查询,是很专业性的,不是⽇常⽤来存储数据的表,需要抽样查询时,才创建和使⽤桶表。
37.Hive ⾃定义 UDF 函数的流程?
- 解答:
- 1)
写⼀个类继承(org.apache.hadoop.hive.ql.)UDF 类
; - 2)
覆盖⽅法 evaluate()
; - 3)
打 JAR 包
; - 4)通过 hive 命令将 JAR
添加
到 Hive 的类路径:
- hive> add jar /home/ubuntu/ToDate.jar;
- 5)
注册函数
:
- hive> create temporary function xxx as ‘XXX’;
- 6)
使⽤函数
; - 7)[可选] drop 临时函数;
38.Hive 可以像关系型数据库那样建⽴多个库吗?
- 可以建⽴多个库
39.Hive 实现统计的查询语句是什么?
- count 等语句。
40.Hive 优化措施
- 可以参考
1.Fetch 抓取
- Hive 中对某些情况的查询可以不必使⽤ MapReduce 计算。
- hive-default.xml.template ⽂件中 hive.fetch.task.conversion 默认是 more,老版本hive是minimal(修改为more)
- more时全局查找、字段查找、limit 查找等都不⾛ mapreduce。
2.本地模式
- 单台机器上处理所有的任务,适合于小数据集,执行时间会大大缩短
- Hive 的输⼊数据量⾮常⼩的情况下
- set hive.exec.mode.local.auto=true; (开启本地模式)
- set hive.exec.mode.local.auto.inputbytes.max=134217728;(小于128mb采用本地模式,默认134217728)
- set hive.exec.mode.local.auto.input.files.max=10;(输入文件个数小于10个采用本地模式,默认为 4)
场景:
我想要验证一个函数的执行结果
我先建一张表xxx,
往表里插入一行数据
select (1+2) from xxx
结果需要好久???
name我可以开启本地模式set hive.exec.mode.local.auto=true;(默认为false)
但是你会发现job确实是以本地模式运行了(看job名字就能看出来,中间有local字样),但是还是会报错,各种找不到jar包。
这里还要运行一个语句:set fs.defaultFS=file:///
在执行sql发现速度大大提高了!
当一个job满足下面条件的时候才能真正使用本地模式
输入数据小于参数:hive.exec.mode.local.auto.inputbytes.max(默认128MB)
map数小于参数:hive.exec.mode.local.auto.tasks.max(默认4)
reduce为0或1
3.表的优化
- 表的优化1.⼩表、⼤表 Join(新版的 hive 已经对⼩表 JOIN ⼤表和⼤表 JOIN ⼩表进⾏了优化。⼩表 放在左边和右边已经没有明显区别。)
- 将 key 相对分散,并且数据量⼩的表放在 join 的左边
- 优点:
- 1.有效减少内存溢出错误发⽣的⼏率
- 2.可以使⽤ Group 让⼩的维度表(1000条以下的记录条数)先进内存
- 3.在 map 端完成 reduce。
- 表的优化2.⼤表 Join ⼤表
空 KEY 过滤
(is not null)
- 有时 join 超时是因为某些 key 对应的数据太多,⽽相同 key 对应的数据都会发送到相同的 reducer 上,从⽽导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下,这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进⾏过滤。例如 key 对应的字段为空
空 key 转换
(concat(‘含空列’,rand()))
- 有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋⼀个随机的值,使得数据随机均匀地分不到不同的 reducer 上。
- 表的优化3.
MapJoin
- 表的优化4.
Group By
- 表的优化5.
Count(Distinct) 去重统计
- 表的优化6.
避免笛卡尔积
- 尽量避免笛卡尔积(join 的时候不加 on 条件,或者⽆效的 on 条件)
- 表的优化7.
⾏列过滤
- 列处理:在 SELECT 中,
只拿需要的列
,如果有,尽量使⽤分区过滤
,少⽤ SELECT *。 - ⾏处理:在分区剪裁中,当使⽤外关联时,如果将副表的过滤条件写在 Where 后⾯,那么就会先全表关联,之后再过滤
- 表的优化8.
动态分区
调整
- 关系型数据库中,对分区表 Insert 数据时候,数据库⾃动会
根据分区字段的值,将数据插⼊到相应的分区中
,Hive 中也提供了类似的机制,即动态分区(Dynamic Partition),只不过,使⽤ Hive 的动态分区,需要进⾏相应的配置。
- 表的优化9.
分桶
- 表的优化10.
分区
优化措施4.数据倾斜
- Map 数
- ⼩⽂件进⾏合并
- 复杂⽂件增加 Map 数
- Reduce 数
优化措施5.并⾏执⾏
优化措施6.严格模式
优化措施7.JVM 重⽤
化措施8.推测执⾏
优化措施9.压缩
优化措施10.EXPLAIN(执⾏计划)
41.Hive 数据分析⾯试题
- 场景举例.北京市学⽣成绩分析.
- 成绩的数据格式:时间,学校,年纪,姓名,科⽬,成绩
- 样例数据如下:
2013,北⼤,1,裘容絮,语⽂,97
2013,北⼤,1,庆眠拔,语⽂,52
2013,北⼤,1,乌洒筹,语⽂,85
2012,清华,0,钦尧,英语,61
2015,北理⼯,3,冼殿,物理,81
2016,北科,4,况飘索,化学,92
2014,北航,2,孔须,数学,70
2012,清华,0,王脊,英语,59
2014,北航,2,⽅部盾,数学,49
2014,北航,2,东⻔雹,数学,77
1 情景题:分组 TOPN
-- 1.分组 TOPN 选出 今年每个学校,每个年级,分数前三的科⽬.
hive -e"set mapreduce.job.queuename=low;
select t.*
from(select
school,
class,
subjects,
score,
row_number() over (partition by school,class,subjects order by score desc) rank_code
from spark_test_wx
where partition_id = "2017"
) t
where t.rank_code <= 3;"
-- 今年,北航,每个班级,每科的分数,及分数上下浮动 2分的总和
select school,class,subjects,score,
sum(score) over(order by score range between 2 preceding and 2 following) sscore
from spark_test_wx
where partition_id = "2017" and school="北航"
提问,上述 sql 有没有可优化的点.
-- row_number() over (distribute by school,class,subjects sort by score desc) rank_code
2 情景题:where 与 having
-- 今年 清华 1 年级 总成绩⼤于 200 分的学⽣ 以及学⽣数
hive -e "
set mapreduce.job.queuename=low;
select school,class,name,sum(score) as total_score,
count(1) over (partition by school,class) nct
from spark_test_wx
where partition_id = "2017" and school="清华" and class = 1
group by school,class,name
having total_score>200;
"
having 是分组(group by)后的筛选条件,分组后的数据组内再筛选,也就是说 HAVING⼦句可以让我们筛选成组后的各组数据。
where则是在分组,聚合前先筛选记录。也就是说作⽤在GROUP BY⼦句和HAVING⼦句前。
3 情景题:数据倾斜
今年加⼊进来了 10 个学校,学校数据差异很⼤计算每个学校的平均分。
该题主要是考察数据倾斜的处理⽅式。
Group by ⽅式很容易产⽣数据倾斜。需要注意⼀下⼏点
1)Map 端部分聚合
hive.map.aggr=true(⽤于设定是否在 map 端进⾏聚合,默认值为真,相当于combine)
hive.groupby.mapaggr.checkinterval=100000(⽤于设定 map 端进⾏聚合操作的条数)
2)有数据倾斜时进⾏负载均衡
设定 hive.groupby.skewindata,当选项设定为 true 是,⽣成的查询计划有两个MapReduce 任务。
在第⼀个MapReduce 中,map 的输出结果集合会随机分布到reduce 中,每个reduce做部分聚合操作,并输出结果。这样处理的结果是,相同的 Group By Key 有可能分发到不同的 reduce 中,从⽽达到负载均衡的⽬的;
第⼆个 MapReduce 任务再根据预处理的数据结果按照 Group By Key 分布到 reduce中(这个过程可以保证相同的 Group By Key 分布到同⼀个 reduce 中),最后完成最终的聚合操作。
4 情景题:分区表
假设我创建了⼀张表,其中包含了 2016 年客户完成的所有交易的详细信息:CREATE TABLE transaction_details (cust_id INT, amount FLOAT, month STRING, country STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘,’;
现在我插⼊了 100 万条数据,我想知道每个⽉的总收⼊。
问:如何⾼效的统计出结果。写出步骤即可。
解答:
1)⾸先分析这个需求,其实并不难,但是由于题⽬说了,要⾼效。⽽且数据量也不⼩,直接写 sql 查询估计肯定会挂。
2)分析:
(1)我们可以通过根据每个⽉对表进⾏分区来解决查询慢的问题。 因此,对于每个⽉我们将只扫描分区的数据,⽽不是整个数据集。
(2)但是我们不能直接对现有的⾮分区表进⾏分区。 所以我们会采取以下步骤来解决这个问题:
(3)创建⼀个分区表,partitioned_transaction:
create table partitioned_transaction (cust_id int, amount float, country string) partitioned by(month string) row format delimited fields terminated by ‘,’;
(4)在 Hive 中启⽤动态分区:
SET hive.exec.dynamic.partition = true;
SET hive.exec.dynamic.partition.mode = nonstrict;
(5)将数据从⾮分区表导⼊到新创建的分区表中:
insert overwrite table partitioned_transaction partition (month) select cust_id, amount,country, month from transaction_details;
(6)使⽤新建的分区表实现需求。
42.hive导入导出
导入
-
本地文件
导入到Hive表–load data local inpath '路径' into/overwrite table 表名
-
HDFS文件
导入到Hive表–load data inpath 'hdfs路径' into/overwrite table 表名
Hive表
导入到Hive表(select 或者insert )
- 创建表的过程中从其他表导入–
create table ... as select xxx from 其他表
- 从其他表导入–
insert into/overwrite table 表名 select xxx from 其他表
- 指定数据库目录在HDFS上的地址–
location 'hdfs路径'
导出
- 导出到本地文件系统;
- insert overwrite local directory ‘/home/wyp/wyp’ select * from wyp;
- 和导入数据到Hive不一样,不能用insert into来将数据导出
- 还可以用hive的-e和-f参数来导出数据。其中-e 表示后面直接接带双引号的sql语句;而-f是接一个文件,文件的内容为一个sql语句
- hive -e “select * from wyp” >> local/wyp.txt
- 导出到HDFS中;
- insert overwrite directory ‘/home/wyp/wyp’ select * from wyp;
- 导出到Hive的另一个表中。
- insert into/overwrite table 表名 select xxx from 其他表
43.Hive的存储格式及压缩算法
存储格式
- TextFile
-
行式存储
:查询一整行的时候,查询快 - 默认格式
- 数据不做压缩,磁盘开销大,数据解析开销大
- 可使用Gzip、Bzip2,但压缩后的文件不支持split
- 在反序列化的时候,必须逐个字段判断是不是分隔符和行结束符,因此反序列化开销高
- SequenceFile
- 行式存储
- ORC
-
列式存储
:查询只有少数几个字段
的时候,大大减少读取的数据量
- 每个ORC文件由3部分组成:Index Data(1w行做一个索引)、Row Data(具体数据)、Stripe Footer(类型,长度)
- Parquent
列式存储
二进制存储
- 会按照Block大小设置行组的大小
压缩算法
- Bzip2
- 可切分
- 压缩率高,高于Gzip,压缩速度很慢
- 适合:对速度要求不高,但需要较大压缩率
- Gzip
- 不可切分
- LZO
- 不可切分
- 压缩率低于Gzip
- 需要建索引,并指定输入格式
- LZ4
- 不可切分
- Snappy
不可切分
高效的压缩速度和合理的压缩率
- 压缩率低于Gzip
44.Hive中小文件问题
产生:
动态分区插入
reduce数量过多
数据源本身包含大量小文件
影响
会开很多map,一个map开一个jvm执行,这些任务的初始化和启动和回收会占用大量资源 会占用大量元数据内存(每个小文件对象150byte左右)
解决
- 不使用textfile
- 减少reduce数量
- 少用动态分区,用的话加上distribute by分区
- 对于已存在的数据
- hadoop archive命令把小文件进行归档
- 重建表,建表时减少reduce数量
- 参数进行调节,设置map/reduce相关参数
- map端/reduce端输出进行合并
- 设置合并文件大小
- 当输出文件的平均大小小于某值时,启动一个独立的MR任务进行文件merge
map/reduce端的相关参数的设置
- 设置map输入合并小文件的相关参数:
//每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size=256000000;
//一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node=100000000;
//一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack=100000000;
//执行Map前进行小文件合并
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
配置Hive结果合并
- 我们可以通过一些配置项来使Hive在执行结束后对结果文件进行合并:
//设置map端输出进行合并,默认为true
set hive.merge.mapfiles = true
//设置reduce端输出进行合并,默认为false
set hive.merge.mapredfiles = true
//设置合并文件的大小
set hive.merge.size.per.task = 256*1000*1000
//当输出文件的平均大小小于该值时,启动一个独立的MapReduce任务进行文件merge。
set hive.merge.smallfiles.avgsize=16000000
- 注意:对于输出结果为压缩文件形式存储的情况,要解决小文件问题,如果在Map输入前合并,对输出的文件存储格式并没有限制。但是如果使用输出合并,则必须配合SequenceFile来存储,否则无法进行合并。
45.Hive中Join的类型和用法
概览:
内关联(JOIN)
- 只返回能关联上的结果。
左外关联(LEFT [OUTER] JOIN)
- 以LEFT [OUTER] JOIN关键字前面的表作为主表,和其他表进行关联,返回记录和主表的记录数一致,关联不上的字段置为NULL。
- 是否指定OUTER关键字,貌似对查询结果无影响。
右外关联(RIGHT [OUTER] JOIN)
- 和左外关联相反,以RIGTH [OUTER] JOIN关键词后面的表作为主表,和前面的表做关联,返回记录数和主表一致,关联不上的字段为NULL。
- 是否指定OUTER关键字,貌似对查询结果无影响。
全外关联(FULL [OUTER] JOIN)
- 以两个表的记录为基准,返回两个表的记录去重之和,关联不上的字段为NULL。
- 是否指定OUTER关键字,貌似对查询结果无影响。
- 注意:FULL JOIN时候,Hive不会使用MapJoin来优化。
LEFT SEMI JOIN
- 以LEFT SEMI JOIN关键字前面的表为主表,返回主表的KEY 也在副表中的记录。
笛卡尔积关联(CROSS JOIN)
- 返回两个表的笛卡尔积结果,不需要指定关联键。
left semi join和left join区别
- LEFT SEMI JOIN 是 IN/EXISTS 子查询的一种更高效的实现。
- LEFT SEMI JOIN 的限制是, JOIN 子句中右边的表只能在 ON 子句中设置过滤条件,在 WHERE 子句、SELECT 子句或其他地方都不行。
- 因为 left semi join 是 in(keySet) 的关系,遇到右表重复记录,左表会跳过,而 join 则会一直遍历。这就导致右表有重复值得情况下 left semi join 只产生一条,join 会产生多条,也会导致 left semi join 的性能更高。
- left semi join 是只传递表的 join key 给 map 阶段,因此left semi join 中最后 select 的结果只许出现左表。因为右表只有 join key 参与关联计算了,而left join on 默认是整个关系模型都参与计算了
实例
- Hive中除了支持和传统数据库中一样的内关联、左关联、右关联、全关联,还支持LEFT SEMI JOIN和CROSS JOIN,但这两种JOIN类型也可以用前面的代替。
- 注意:Hive中Join的关联键必须在ON ()中指定,不能在Where中指定,否则就会先做笛卡尔积,再过滤。
- 数据准备
hive> desc lxw1234_a;
OK
id string
name string
Time taken: 0.094 seconds, Fetched: 2 row(s)
hive> select * from lxw1234_a;
OK
1 zhangsan
2 lisi
3 wangwu
Time taken: 0.116 seconds, Fetched: 3 row(s)
hive> desc lxw1234_b;
OK
id string
age int
Time taken: 0.159 seconds, Fetched: 2 row(s)
hive> select * from lxw1234_b;
OK
1 30
2 29
4 21
Time taken: 0.09 seconds, Fetched: 3 row(s)
- 内关联(JOIN)
- 只返回能关联上的结果。
SELECT a.id,
a.name,
b.age
FROM lxw1234_a a
join lxw1234_b b
ON (a.id = b.id);
--执行结果
1 zhangsan 30
2 lisi 29
- 左外关联(LEFT [OUTER] JOIN)
- 以LEFT [OUTER] JOIN关键字前面的表作为主表,和其他表进行关联,返回记录和主表的记录数一致,关联不上的字段置为NULL。
- 是否指定OUTER关键字,貌似对查询结果无影响。
SELECT a.id,
a.name,
b.age
FROM lxw1234_a a
left join lxw1234_b b
ON (a.id = b.id);
--执行结果:
1 zhangsan 30
2 lisi 29
3 wangwu NULL
- 右外关联(RIGHT [OUTER] JOIN)
- 和左外关联相反,以RIGTH [OUTER] JOIN关键词后面的表作为主表,和前面的表做关联,返回记录数和主表一致,关联不上的字段为NULL。
- 是否指定OUTER关键字,貌似对查询结果无影响。
SELECT a.id,
a.name,
b.age
FROM lxw1234_a a
RIGHT OUTER JOIN lxw1234_b b
ON (a.id = b.id);
--执行结果:
1 zhangsan 30
2 lisi 29
NULL NULL 21
- 全外关联(FULL [OUTER] JOIN)
- 以两个表的记录为基准,返回两个表的记录去重之和,关联不上的字段为NULL。
是否指定OUTER关键字,貌似对查询结果无影响。 - 注意:FULL JOIN时候,Hive不会使用MapJoin来优化。
SELECT a.id,
a.name,
b.age
FROM lxw1234_a a
FULL OUTER JOIN lxw1234_b b
ON (a.id = b.id);
--执行结果:
1 zhangsan 30
2 lisi 29
3 wangwu NULL
NULL NULL 21
- LEFT SEMI JOIN
- 以LEFT SEMI JOIN关键字前面的表为主表,返回主表的KEY也在副表中的记录。
SELECT a.id,
a.name
FROM lxw1234_a a
LEFT SEMI JOIN lxw1234_b b
ON (a.id = b.id);
--执行结果:
1 zhangsan
2 lisi
--等价于:
SELECT a.id,
a.name
FROM lxw1234_a a
WHERE a.id IN (SELECT id FROM lxw1234_b);
--也等价于:
SELECT a.id,
a.name
FROM lxw1234_a a
join lxw1234_b b
ON (a.id = b.id);
--也等价于:
SELECT a.id,
a.name
FROM lxw1234_a a
WHERE EXISTS (SELECT 1 FROM lxw1234_b b WHERE a.id = b.id);
- 笛卡尔积关联(CROSS JOIN)
- 返回两个表的笛卡尔积结果,不需要指定关联键。
SELECT a.id,
a.name,
b.age
FROM lxw1234_a a
CROSS JOIN lxw1234_b b;
--执行结果:
1 zhangsan 30
1 zhangsan 29
1 zhangsan 21
2 lisi 30
2 lisi 29
2 lisi 21
3 wangwu 30
3 wangwu 29
3 wangwu 21
- 除非特殊需求,并且数据量不是特别大的情况下,才可以慎用CROSS JOIN,否则,很难跑出正确的结果,或者JOB压根不能执行完。
- Hive中只要是涉及到两个表关联,首先得了解一下数据,看是否存在多对多的关联。
46.Hive严格模式
- 开启后禁止3种类型查询
- 分区表没有指定分区字段为过滤条件的查询
- order by不加limit的查询
- 笛卡尔积的查询
- Hive严格模式
- Hive提供了一个严格模式,可以防止用户执行那些可能产生意向不到的不好的效果的查询。说通俗一点就是这种模式可以阻止某些查询的执行。通过如下语句设置严格模式:
hive> set hive.mapred.mode=strict;
- 设置为严格模式后,可以禁止3种类型的查询:
- (1):带有分区的表的查询
- 如果在一个分区表执行hive,
除非where语句中包含分区字段过滤条件来显示数据范围
,否则不允许执行。换句话说就是在严格模式下不允许用户扫描所有的分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。如果不进行分区限制的查询会消耗巨大的资源来处理,如下不带分区的查询语句:
hive> SELECT DISTINCT(planner_id) FROM fracture_ins WHERE planner_id=5;
- 执行后会出现如下错误:
FAILED: Error in semantic analysis: No Partition Predicate Found for Alias "fracture_ins" Table "fracture_ins
- 解决方案是在where中增加分区条件:
hive> SELECT DISTINCT(planner_id) FROM fracture_ins
> WHERE planner_id=5 AND hit_date=20120101;
- (2):带有order by的查询
- 对于使用了order by的查询,要求必须有limit语句。因为order by为了执行排序过程会将所有的结果分发到同一个reduce中进行处理,强制要求用户增加这个limit语句可以防止reduce额外消耗资源,如下是不带limit关键字的查询语句:
hive> SELECT * FROM fracture_ins WHERE hit_date>2012 ORDER BY planner_id;
- 出现如下错误:
FAILED: Error in semantic analysis: line 1:56 In strict mode,
limit must be specified if ORDER BY is present planner_id
- 解决方案就是增加一个limit关键字:
hive> SELECT * FROM fracture_ins WHERE hit_date>2012 ORDER BY planner_id
> LIMIT 100000;
- (3):限制笛卡尔积的查询
- 对关系型数据库非常了解的用户可能期望在执行join查询的时候不使用on语句而是使用where语句,这样关系型数据库的执行优化器就可以高效的将where语句转换成那个on语句了。不幸的是,Hive并不支持这样的优化,因为如果表非常大的话,就会出现不可控的情况,如下是不带on的语句:
hive> SELECT * FROM fracture_act JOIN fracture_ads
> WHERE fracture_act.planner_id = fracture_ads.planner_id;
- 出现如下错误:
FAILED: Error in semantic analysis: In strict mode, cartesian product
is not allowed. If you really want to perform the operation,
+set hive.mapred.mode=nonstrict+
- 解决方案就是加上on语句:
hive> SELECT * FROM fracture_act JOIN fracture_ads
> ON (fracture_act.planner_id = fracture_ads.planner_id);
47.sparkSQL一定比hive快吗,能否想出一种场景,sparkSQL比hive慢(重点)
sparkSQL之所以快
- 中间阶段不落盘
-
Hadoop 每次 shuffle 操作后,必须写到磁盘,而 Spark 在 shuffle 后不一定落盘,可以 cache 到内存中,以便迭代时使用。
如果操作复杂,很多的 shufle 操作,那么 Hadoop 的读写 IO 时间会大大增加,也是 Hive 更慢的主要原因了。
- 消除了冗余的 MapReduce 阶段
- Hadoop 的 shuffle 操作一定连着完整的 MapReduce 操作,冗余繁琐。而 Spark 基于
RDD
提供了丰富的算子操作,且 reduce 操作产生 shuffle 数据,可以缓存在内存中。
- JVM 的优化
- Hadoop 每次
MapReduce
操作,启动一个 Task 便会启动一次 JVM,基于进程
的操作。而Spark 每次 MapReduce 操作是基于线程的,只在启动 Executor 是启动一次 JVM,内存的 Task 操作是在线程复用
的。每次启动 JVM 的时间可能就需要几秒甚至十几秒,那么当 Task 多了,这个时间 Hadoop 不知道比 Spark 慢了多少。
- 极端查询
- 这个查询
只有一次 shuffle 操作
,此时,也许 Hive HQL 的运行时间也许比 Spark 还快,反正 shuffle 完了都会落一次盘,或者都不落盘。
Select month_id
, sum(sales)
from T
group by month_id;