杂谈
hive
不是数据库, 更不是关系型数据库, 它是计算框架
它不存在索引的概念, 而是依靠并行处理提高的效率distribute by
+ 指定reduceTask的数量, 可以在一定程度上, 依据键切分源表.
但是distribute by
保证相同键的元素在相同分区, 但不保证分区中只有相同的键
因此这个切分是很不稳定的, 不建议使用
顺便一提, String格式的键进行distribute by时, 默认按照尾字符的哈希值进行分区, 也就是说, “1”, “21”, "651"都可能在同一个分区- Hive流程: 解析, 编译, 优化, 执行
- 分桶和分区都是为了消峰
Hive的缺点
- 迭代式算法无法表达
- 数据挖掘方面不擅长
Hive加载分区的几种方式
- hdfs上创建对应文件夹后, 补充元数据:
msck repair table dept_partition2;
- hdfs上创建对应文件夹后, 新增分区:
alter table table_name add partiton (city string);
- load
hive调优
- 查看执行计划.
explain select * from table;
- 查看详细执行计划.
explain extended select * from table;
0. 运行顺序
次序 | 命令 |
---|---|
1 | from |
2 | join |
3 | on |
4 | where |
5 | group by |
6 | having |
7 | over |
8 | select |
9 | distinct |
10 | order by |
11 | limit |
1. Fetch抓取
设置hive.fetch.task.conversion=more
, 简单查询不调用mr. 相反的是none
2. 本地模式
设置hive.exec.mode.local.auto=true
, 默认要求的输入数据量小于128M, 输入文件少于4个, reduceTash少于1个.
3. map端聚合
- 是否在Map端进行聚合, 默认为True.
hive.map.aggr = true
- 在Map端进行聚合操作的条目数目.
hive.groupby.mapaggr.checkinterval = 100000
- 有数据倾斜的时候进行负载均衡(默认是false).
hive.groupby.skewindata = true
会进行两次map, 第一次将数据倾斜的key分散到不同的map, 第二次聚合相同的key. 拉低效率, 且多一次shuffle, 会给带宽带来很大压力
4. 表优化
- 小表join大表, 也就时map端join. 新版本的hive已经对此完成了自优化(放左放右没影响), map端join是默认打开的,
hive.auto.convert.join=true
- 空
key
之间的join
, 会导致笛卡尔积, 此时可以加盐 hive
指令中,distinct
会将结果聚合到一个reduce
中, 所以要避免使用.group by
可以达到相同效果.- 表
join
时, 过滤条件写在on
中, 而不是where
中. 因为join
比where
更先触发
5. 动态分区
- 开启动态分区(默认true).
hive.exec.dynamic.partition=true
- 设置为非严格模式.
hive.exec.dynamic.partition.mode=nonstrict
- 在所有执行MR的节点上,最大一共可以创建多少个动态分区.
hive.exec.max.dynamic.partitions=1000
- 在每个执行MR的节点上,最大可以创建多少个动态分区. 如果需要以天为单位分区, 一年时365个分区. 默认值是100会报错.
hive.exec.max.dynamic.partitions.pernode=100
- 整个MR Job中, 最大可以创建多少个HDFS文件.
hive.exec.max.created.files=100000
- 空分区生成时,是否抛出异常, 默认
false
.hive.error.on.empty.partition=false
- 开启自动合并小文件.
hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
- 调整分片, 控制
mapTask
的运行时间在30s左右 - 开启严格模式
6. hadoop端优化(mapred-site.xml)
- 开启jvm重用,
mapreduce.job.jvm.numtasks=10
. 缺点是并行度低的时候, 效率快的task - 推测执行,
mapreduce.map.speculative=true
. 推测执行的缺点是, 重新计算会导致对资源和带宽的极大浪费 - hive中也可以设置开启推测执行.
hive.mapred.reduce.tasks.speculative.execution=true
hive语法补充
explode和lateral view
1. 拆分array
array = Array(1, 2, 3, 4)
直接展开:select explode(array) arr from table;
聚合: select sum(lvtable.arr) from table lateral view explode(array) lvtable as arr;
later view
可以视为一张表, 可以直接于原表做笛卡尔积后进行展示, 也可以聚合
2. 拆分map
# -- map = {name: wang, age: 18}
# select explode(map) as one, two from table;
# -- 显示结果
> name wang
> age 18
group by聚合为集合
group by可以将聚合的元素去重后, 汇总为集合
sport_id | name |
---|---|
1 | a |
1 | b |
1 | c |
2 | c |
2 | c |
select id,collect_set(name) from test group by id;
sport_id | set(name) |
---|---|
1 | [a, b, c] |
2 | [c] |
其它
hive
也有&
,|
,^
这些位运算符- <>和!=区别: <>是sql标准语言, !=不够标准
count(if 1 or null)
是mysql语法, hive不支持, 可以用case when
达到类似效果between 1 and 2
, 前后都包含rlike
正则匹配
常用函数
方法 | 作用 |
---|---|
round(double[, int]) | 四舍五入, 第二个参数控制精确度, 默认是0, 个位 |
current_timestamp() | 当前时间戳(毫秒级), 如2019-06-21 12:11:53.028 |
unix_timestamp(string) | 用于转换String为long型时间戳, unix_timestamp("20190621", "yyyyMMdd") |
date_add(string, int) | 增加指定天数, date_add('2017-07-01', 1) |
datediff(string, string) | 计算日期差, diffdate('2017-07-02', '2017-07-01') 结果是1 |
nvl | 空值替换 |