1.Hive内部表和外部表的区别?
内部表的数据由Hive管理,外部表的数据不由Hive管理。
在Hive中删除内部表后,不仅会删除元数据还会删除存储数据,
在Hive中删除外部表后,只会删除元数据但不会删除存储数据。
内部表一旦创建,就会同时创建一个映射路径:/hive312/warehouse/DBNAME.db/TABLENAME
外部表创建后并不会同时创建一个映射路径,需要自行指定location。
内部表创建之后,通常表中还没有数据,需要通过load data向成表中输入数据。
外部表创建之后,通常表中已有数据。
2.数仓为什么要进行分层?
- 用空间换时间,通过大量的预处理来提升应用系统的用户体验(效率),因此数据仓库会存在大量冗余的数据。
- 如果不分层的话,如果源业务系统的业务规则发生变化将会影响整个数据清洗过程,工作量巨大。
(在实际业务环境中,源业务系统的数据结构和业务规则经常会发生变化。) - 通过数据分层管理能够简化数据清洗的过程。
3.SORT BY和ORDER BY的区别?
ORDER BY是对数据进行全局排序,SORT BY是对每个Reducer中的数据进行单独排序。当Reducer的数量为1时,ORDER BY和SORT BY都是全局排序。
ORDER BY的排序列可以不为SELECT中出现的指定列,SORT BY的排序列必须为SELECT中出现的指定列。
ORDER BY适用于小数据集,性能较差;SORT BY适用于大数据集。
对大数据集进行部分排序,则用DISTRIBUTE BY+SORT BY;对大数据集进行全局排序,则用(DISTRIBUTE BY+SORT BY|CLUSTER BY)+ORDER BY.
DISTRIBUTE BY和CLUSTER BY的区别?
DISTRIBUTE BY是确定数据被分配到哪个Reducer中,CLUSTER BY相当于对同一个字段进行DISTRIBUTE BY+SORT BY。
4.关于Hive有哪些常见的优化?
- Hive MapJoin
配置:
set hive.auto.convert.join = true(默认开启) – 开启mapjoin操作
set hive.mapjoin.smalltable.filesize=25000000; – 重新定义小表边界,如果内存空闲,则可以调大
set hive.optimize.bucketmapjoin=false; – 对分桶表不做MapJoin
其他:
可以设置为不等值连接
不适用的情况:
a.“联合”(除UNION ALL)之前,"分组排序"之后
在UNION ALL, LATERAL VIEW, GROUP BY/JOIN/SORT BY/CLUSTER BY/DISTRIBUTE BY等操作后面
在UNION, JOIN 以及其他 MAPJOIN之前
b.仅适用于"大表+小表"的情况,不适用于多张表或复杂排序的情况
-
Hive Reducer优化
** 设置特定MapReduce作业的reducer数量
默认为-1,表示Hive将自动决定Reducer的数量
set mapreduce.job.reduces=; ✔
set mapred.reduce.tasks=;
** 单个Reducer最大处理的字节数
默认为256000000,为256兆 ≈ 2*Block
set hive.exec.reducers.bytes.per.reducer=;
** 限制任何Hive查询可能使用的reducer的最大数量
默认为1009
Reducer数量距离最大机器数1024还有一定余量的原因:如果集群的机器数>1000台,那么每台机器不一定都有DN,则有一些机器单独跑NN,那么这些机器就没有NM,也就不会分配容器跑Reducer.
set hive.exec.reducers.max=;
** 面试:Reducer的数量为什么不是越多越好?
1.资源浪费,本应分配给其他任务和节点的资源被分配给Reducer。
2.会花费过多的时间在上下文切换上而非任务处理。
3.系统需要管理更多的Reducer,增加了调度和通信的开销。 -
简化排序列的表示
set hive.groupby.orderby.position.alias=true|false
当该属性设置为true
时,允许在GROUP BY存在时在ORDER BY子句使用排序列编号替代字段。 -
Fetch抓取
Hive中对某些情况的查询可以不必使用MapReduce计算,例如:SELECT * FROM employees;
将hive.fetch.task.conversion
设置为more即可实现不走MapReduce,走Fetch。 -
本地模式
对于小数据集,采取本地模式在单台机器上处理所有的任务即可,不必分配给多台机器进行处理,可以明显缩短执行时间。
set hive.exec.mode.local.auto=true// 开启本地mr
set hive.exec.mode.local.auto.inputbytes.max=50000000;// 设置local mr的最大输入数据量
set hive.exec.mode.local.auto.input.files.max=10;//设置local mr的最大输入文件个数 -
GROUP BY优化
默认情况下,Map阶段同一Key数据分发给一个Reduce,当一个Key数据过大时就倾斜了。
并不是所有的聚合操作都需要在Reducer端完成,很多聚合操作都可以现在Map端完成部分聚合,最终再Reducer端得出最终结果。
set hive.map.aggr=true;//开启Map端聚合
set hive.groupby.mapaggr.checkinterval=100000;//设置在Map端进行聚合操作的数据条目数目
set hive.groupby.skewindata=true;//有数据倾斜时进行负载均衡 -
行列过滤
列处理:只查询需要的列
行处理:表连接时,先过滤数据再进行表连接 -
动态分区
SET hive.exec.dynamic.partition = true;
SET hive.exec.dynamic.partition.mode = nonstrict; -
开启并行执行(并行的前提是系统资源比较空闲)
Hive会将一个查询转化成一个或者多个阶段,这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段…或者其他在Hive执行中可能需要的阶段。
Hive默认一次只会执行一个阶段,但是对于可以并行执行的、非相互依赖的阶段,可以设置并行执行。
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=16;//同一个SQL允许最大并行度,默认为8。 -
开启严格模式:防止用户执行一些查询方式。
严格模式:
set hive.mapred.mode=strict
严格模式可以禁止的3类查询:
1.对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。
2.对于使用了order by语句的查询,要求必须使用limit语句。rder by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。
3.限制笛卡尔积的查询。 -
选择合适的文件格式
使用列式存储格式(如Parquet,ORC)可以显著提高查询性能。 -
优化数据存储和加载
- 使用数据存储:可以使用Snappy压缩格式
- 合理选择数据分隔符
-
开启Vetorization
启用Vectorization可以使Hive在执行查询时一次处理一批数据,而不是逐行处理,从而显著提高性能。
set hive.vectorized.execution.enabled=true -
EXPLAIN HQL
执行计划分析,进行CBO,选择最优的执行计划。 -
Hive可以配置为使用Tez执行引擎替代传统的MapReduce
set hive.execution.engine=tez
5.Hive的各种存储格式
面向行:
TextFile,SequenceFile
面向列:
RCFile,ORCFile,Parquet
6.如何处理数据倾斜问题?
A.先尝试内置配置优化
set hive.map.aggr=true;
set hive.groupby.skewindata=true;
distribute by | skewed by
set hive.exec.parallel=true
…
B.如果内置配置效果不佳,再尝试进行自定义的配置
确定倾斜数据 —— 计算分割因子 —— 形成新分组键
7.简述Hive主要架构
UI提交查询到Driver,Driver通过Compiler,再通过MetaStore指定的存储元数据的Mysql数据库获取元数据并且根据元数据解析查询表达式,生成执行计划。
执行计划通过一系列优化和从AGT到逻辑执行计划到物理执行计划的变化最终将执行计划传到执行引擎,
执行引擎选取合适的执行工具和执行顺序来处理执行计划。
8.Hive中排序函数的区别?
ROW NUMBER():无重复行号
RANK():重复排名跳号
DENSE_RANK():重复排名不跳号
9.Hive如何实现分区?
分区分为两种方式,静态分区和动态分区。
静态分区的基本思路是将筛选好的数据放到指定的分区下,筛选数据又分为两种方式,第一种,对于简单的数据筛选或过滤,
可以在Shell中进行筛选并且重定向到一个结果文件,再通过load data local path的方式将该结果文件导入到分区中。
动态分区的基本思路是一次性将多个分区的数据导入相应的分区中,动态分区在使用前还需要进行配置。
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
10.Hive如何进行数据的导入和导出?
导入
INSERT方式
INSERT INTO TABLE TABLE_NAME VALUES(1,'zhanshan');
IMPORT方式
IMPORT TABLE TABLE_NAME [PARTITION(pf1=v1,...,pf2=v2)] FROM 'HDFS_PATH'
LOAD方式(通常用于内部表创建后的数据导入)
load data [local] inpath 'FILEDIR' [overwrite] into table DB_NAME.TABLE_NAME;
LOCATION方式(通常用于外部表创建后的数据导入)
CREATE EXTERNAL TABLE TABLE_NAME IF NOT EXISTS(
...
)
location '...'
location指定的路径是实现创建好的,并且该路径下已经提前存放好了数据文件
AS SELECT | AS SELECT WITH 方式
create table hive_ext_test_before2015 as
select * from hive_ext_regex_test1w
where year(order_time) <= 2015;
CREATE TABLE hive_test_before2015_and_male_over5or5w_after2015 AS
WITH
before2015 AS (
SELECT * FROM hive_ext_regex_test1w
WHERE YEAR(order_time)<=2015
),
agg_male_over5or5w AS (
SELECT user_id
FROM hive_ext_regex_test1w
WHERE YEAR(order_time)>2015 AND user_gender = '男'
GROUP BY user_id
HAVING COUNT(*) >= 5 OR SUM(order_amount) >= 50000
),
male_over5or5w AS (
SELECT * FROM hive_ext_regex_test1w A
INNER JOIN agg_male_over5or5w B
ON A.user_id = B.user_id AND YEAR(A.order_time)>2015
)
SELECT * FROM before2015
UNION ALL
SELECT * FROM male_over5or5w;
导出
INSERT方式,查询结果导出到本地或HDFS
写表操作
单次
INSERT OVERWRITE INTO TABLE [DBNAME].TABLENAME [PARTITION(f1,...,fn)]
SELECT F1,F2... FROM SOURCE_TABLE;
多次
FROM SOURCE_TABLE
INSERT OVERWRITE|INTO TABLE [DB_NAME].TBL_NAME1 [PARTITION(pf1,...pfn)]
SELECT ...
WHERE ...
INSERT OVERWRITE|INTO TABLE [DB_NAME].TBL_NAME2 [PARTITION(pf1,...pfn)]
SELECT ...
写盘操作
单次
INSERT OVERWRITE [local] DIRECTORY ...
SELECT F1,F2... FROM SOURCE_TABLE;
多次
FROM SOURCE_TABLE
ROW FORMAT SERDE|DELIMITED
(
fields terminated by '|'
collection items terminated by ','
map keys terminated by ':'
)
STORED AS ...
INSERT OVERWRITE [local] directory 'ABS_PATH1'
SELECT ...
[ROW FORMAT SERDE|DELIMITED ...]
INSERT OVERWRITE [local] directory 'ABS_PATH2'
SELECT ... ;
Hadoop命令导出
dfs -get /user/hive/warehouse/student/ 000000_0 /root/hadoop/student.txt
Shell命令导出
hive -e ‘select id,name from student;’ > /root/hadoop/student.txt
EXPORT方式
EXPORT TABLE TABLE_NAME [PARTITION(pf1=v1,...,pf2=v2)] TO 'HDFS_PATH'
-get /user/hive/warehouse/student/ 000000_0 /root/hadoop/student.txt
Shell命令导出
hive -e ‘select id,name from student;’ > /root/hadoop/student.txt
EXPORT方式
EXPORT TABLE TABLE_NAME [PARTITION(pf1=v1,...,pf2=v2)] TO 'HDFS_PATH'
SQOOP导出