总结一下Hive面试宝典,方便读者快速过一遍Hive面试所需要的知识点
# Hive架构简易示意
Meta Store ->
Client (CLI/JDBC/WebGUI +
Driver/驱动 +
SQL Parser/解析器 +
Physical Plan/编译器 +
QueryOptimizer/优化器 +
Execution/执行器) ->
MapReduce ->
HDFS
语义分析器(semantic analyzer)
和 逻辑策略生成器(logical plan generator)
${hive.metastore.warehouse.dir}
目录下一个文件夹alter table test SET SERDEPROPERTIES('serialization.null.format' = 'a');
来修改metadata
和元数据商店metastore
的作用关系型数据库(RDBMS)
中,如derby、mysql等metadata
的方式org.apache.hadoop.mapred.TextInputFormat和org.apache.hive.ql.io.HiveIgnoreKeyTextOutputFormat;
org.apache.hadoop.hive.ql.io.RCFileInputFormat和org.apache.hadoop.hive.ql.io.RCFileOutputFormat;
每个task只输出单个文件,减少namenode负载;
支持各种复杂的数据类型,比如:datetime,decima以及复杂类型struct、list、map;
文件中存储了一些轻量级的索引数据;
基于数据类型的块模式压缩:integer类型的列用行程长度编码,string类型的列使用字典编码;
用多个相互独立的recordReaders并行读相同的文件
无需扫描markers即可分割文件
绑定读写所需内存
metadata存储用protocol buffers,支持添加和删除列
org.apache.hadoop.mapred.SequenceFileInputFormat和org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat;
在考虑如何压缩那些将由MapReduce处理的数据时,考虑压缩格式是否支持分割是很重要的。
考虑存储在HDFS中的未压缩的文件,其大小为1GB,HDFS的块大小为64MB,所以该文件将被存储为16块。
将此文件用作输入的MapReduce作业会创建1个输人分片(split,也称为“分块”。对于block,我们统一称为“块”。)
每个分片都被作为一个独立map任务的输入单独进行处理
现在假设,该文件是一个gzip格式的压缩文件,压缩后的大小为1GB。和前面一样,HDFS将此文件存储为16块。
然而,针对每一块创建一个分块是没有用的,因为不可能从gzip数据流中的任意点开始读取,map任务也不可能独立于其他分块只读取一个分块中的数据。
gzip格式使用DEFLATE来存储压缩过的数据,DEFLATE将数据作为一系列压缩过的块进行存储。
问题是,每块的开始没有指定用户在数据流中任意点定位到下一个块的起始位置,而是其自身与数据流同步。
因此,gzip不支持分割(块)机制。
在这种情况下,MapReduce不分割gzip格式的文件,因为它知道输入是gzip压缩格式的(通过文件扩展名得知),而gzip压缩机制不支持分割机制。
因此一个map任务将处理16个HDFS块,且大都不是map的本地数据。
与此同时,因为map任务少,所以作业分割的粒度不够细,从而导致运行时间变长。
可使用以下三种标准对压缩方式进行评价:
压缩比:压缩比越高,压缩后文件越小,所以压缩比越高越好。
压缩时间:越快越好。
已经压缩的格式文件是否可以再分割:可以分割的格式允许单一文件由多个Mapper程序处理,可以更好的并行化。
BZip2有最高的压缩比但也会带来更高的CPU开销,Gzip较BZip2次之。
如果基于磁盘利用率和I/O考虑,这两个压缩算法都是比较有吸引力的算法。
LZO和Snappy算法有更快的解压缩速度,如果更关注压缩、解压速度,它们都是不错的选择。
LZO和Snappy在压缩数据上的速度大致相当,但Snappy算法在解压速度上要较LZO更快。
Hadoop的会将大文件分割成HDFS block(默认64MB)大小的splits分片,每个分片对应一个Mapper程序。
在这几个压缩算法中 BZip2、LZO、Snappy压缩是可分割的,Gzip则不支持分割。
jar
拷贝至Hive/lib
目录下hive/conf
下的hive-site.xml
配置文件,添加如下属性:
hbase.zookeeper.quorum
hadoop
hbase_table_1
,指定数据存储在Hbase表中,主要是通过stored by HBaseStorageHandler
类来实现hbase_table_1
表中插入数据Hive的分区分桶都是数据存储和组织的策略,分区类似文件的分类归档,分桶类似于传统数据库的索引
PARTITIONED BY (name string)
,分区键不能和任何列重名PARTITION(name="fx67ll")
SHOW PARTITIONAS
WHERE name = "fx67ll"
ROW FORMAT DELIMITED
# 每个字段之间由[ , ]分割
FIELDS TERMINATED BY ','
# 字段是Array形式,元素与元素之间由[ - ]分割
COLLECTION ITEMS TERMINATED BY '-'
# 字段是K-V形式,每组K-V对内部由[ : ]分割
MAP KEYS TERMINATED BY ':';
set hive.enforce.bucketing = true
CLUSTERED BY(id) INTO 3 BUCKETS
=
指定分区值;动态分区只需要给出分出分区键名称
# 开启动态分区功能,默认false
set hive.exec.dynamic.partition = true
# 允许所有分区都是动态的,否则必须有静态分区字段,默认strict
set hive.exec.dynamic.partition.mode = nonstrict
# 每个mapper或reducer可以允许创建的最大动态分区个数,默认是100,超出则会报错
set hive.exec.max.dynamic.partitions.pernode = 1000
# 一个动态分区语句可以创建的最大动态分区个数,默认是1000,超出报错
set hive.exec.max.dynamic.partitions = 10000
# 全局可以创建的最大文件个数,默认是10000,超出报错
set hive.exec.max.created.files =100000
external
修饰,表数据保存在Hive默认的路径下,数据完全由Hive管理,删除表时元数据(metadata)和表数据都会一起删除external
修饰,表数据保存在HDFS上,该位置由用户指定,删除表时,只会删除表的元数据(metadata)hive.metastore.warehouse.dir
,默认是 /user/hive/warehouse
/user/hive/warehouse
文件夹下以外部表的表名创建一个文件夹,并将属于这个表的数据存放在这里MSCK REPAIR TABLE table_name
Antlr
定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树QueryBlock
QueryBlock
,翻译为执行操作树OperatorTree
OperatorTree
变换,合并不必要的ReduceSinkOperator
,减少shuffle
数据量OperatorTree
,翻译为MapReduce
任务MapReduce
任务的变换,生成最终的执行计划题目:A、B两表,找出ID字段中,存在A表,但是不存在B表的数据。A表总共13w数据,去重后大约3W条数据,B表有2W条数据,且B表的ID字段有索引
select * from B
where (select count(1) as num from A where A.ID = B.ID) = 0
参考下面Hive查询的时候on和where有什么区别的理解二
1. select * from a left join b on a.id = b.id and a.dt=20181115;
2. select * from a left join b on a.id = b.id and b.dt=20181115;
3. select * from a join b on a.id = b.id and a.dt=20181115;
4. select * from a left join b on a.id = b.id where a.dt=20181115;
sql1: 如果是left join 在on上写主表a的条件不会生效,全表扫描。
sql2: 如果是left join 在on上写副表b的条件会生效,但是语义与写到where 条件不同
sql3: 如果是inner join 在on上写主表a、副表b的条件都会生效
sql4: 建议这么写,大家写sql大部分的语义都是先过滤数据然后再join,所以在不了解join on+条件的情况下,条件尽量别写在on后,
直接写到where后就ok了,如果where条件后写b表的过滤条件,就变成了先left join出结果再按照b条件过滤数据
on
是在生成连接表的起作用的,where
是生成连接表之后对连接表再进行过滤left join
时,无论on
的条件是否满足,都会返回左表的所有记录,对于满足的条件的记录,两个表对应的记录会连接起来,对于不满足条件的记录,那右表字段全部是nullright join
时,类似,只不过是全部返回右表的所有记录inner join
时,功能与where
完全相同经过亲测后,更加深了对on和where的理解,得出以下结论:
1.ON后的条件如果有过滤主表的条件,则结果对于不符合该条件的主表数据也会原条数保留,只是不匹配右表数据而已。对于on后面对右表的过滤条件,连接时会用该条件直接过滤右表数据后再和左边进行左连接。总之,对于不满足on后面的所有条件的数据,左表会在结果数据中原条数保留数据,只是不匹配右表数据而已。不满足条件的右表数据各字段会直接以NULL连接主表。
2.ON后对左表的筛选条件对于结果行数会被忽略,但会影响结果中的匹配右表数据,因为只有符合左表条件的数据才会去和符合条件的右表数据进行匹配,不符合条件的左表数据会保留在最后结果中,但匹配的右表数据都是NULL.因此,对于需要过滤左表数据的话,需要把过滤条件放到where后面。
3.ON后的左表条件(单独对左表进行的筛选条件)对于结果行数无影响,还是会返回所有左表的数据,但和右表匹配数据时,系统只会拿左表符合条件(ON后的对左表过滤条件)的数据去和右表符合条件(ON后的对右表过滤条件)的数据进行匹配抓取数据,而不符合条件的左表数据还是会出现在结果列表中,只是对应的右表数据都是NULL。
4.ON后的右表条件(单独对右表进行的筛选条件)会先对右表进行数据筛选后再和左表做连接查询,对结果行数有影响(当左表对右表是一对多时),但不会影响左表的显示行数,然后拿符合条件的右表数据去和符合条件的左表数据进行匹配。
5.Where还是对连接后的数据进行过滤筛选,这个无异议。
6.匹配数据时无论左右表,都是拿符合ON后的过滤条件去做数据匹配,不符合的会保留左表数据,用NULL填充右表数据。
综上得出,ON后面对于左表的过滤条件,在最后结果行数中会被忽略,并不会先去过滤左表数据再连接查询,但是ON后的右表条件会先过滤右表数据再连接左表进行查询。
连接查询时,都是用符合ON后的左右表的过滤条件的数据进行连接查询,只有符合左右表过滤条件的数据才能正确匹配,剩下的左表数据会正常出现在结果集中,但匹配的右表数据是NULL。因此对于左表的过滤条件切记要放到Where后,对于右表的过滤条件要看情况了。如果需要先过滤右表数据就把条件放到ON后面即可。
DISTINCT
DISTINCT
应用到多个字段的时候,DISTINCT
必须放在开头,其应用的范围是其后面的所有字段,而不只是紧挨着它的一个字段,而且DISTINCT
只能放到所有字段的前面DISTINCT
对NULL
是不进行过滤的,即返回的结果中是包含NULL
值的DISTINCT
,如count()
会过滤掉为NULL
GROUP BY
GROUP BY
后面所有字段去重,并不能只对一列去重ROW_NUMBER() OVER
窗口函数order by
会对输入做全局排序,为保证全局的排序,因此只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。sort by
不是全局排序,其在数据进入reducer前完成排序。因此,如果用sort by
进行排序,则sort by
只保证每个reducer的输出有序,不保证全局有序。distribute by 字段
根据指定的字段将数据分到不同的reducer,且分发算法是hash散列,常用sort by
结合使用,Hive要求distribute by
语句要写在sort by
语句之前。cluster by 字段
除了具有distribute by
的功能(既可以把数据分到不同的reduce)外,还会对该字段进行排序。但是排序只能是倒序排序,不能指定排序规则为asc
或者desc
order by
,使用用 distribute by + sort by
distribute by
和 sort by
字段是同一个时,此时,cluster by = distribute by + sort by
split
/ coalesce
/ collect list
/ collect set
application_id
application_id
去yarn上查看运行状态该模块请参考我关于Hive优化
的文章
我是 fx67ll.com,如果您发现本文有什么错误,欢迎在评论区讨论指正,感谢您的阅读!
如果您喜欢这篇文章,欢迎访问我的 本文github仓库地址,为我点一颗Star,Thanks~
转发请注明参考文章地址,非常感谢!!!