Hive的优化
1. 查询join的优化
1. 尽量不使用子查询、尽量不使用in 或者not in (可以使用 [not] exists替代)
2. 尽量避免join连接查询,但是通常避免不了
3. 查询永远是小表驱动大表(小表作为驱动表)
2. 半开连接
在hive中,有一种专有的join操作,left semi join,我们称之为半开连接。它是left join的一种优化形式,只能查询左表的信息,主要用于解决hive中左表的数据是否存在的问题。
select distinct * from student left semi join score on (score.s_id=student.s_id and score.c_id='01');
select distinct * from student
where exists (
select 1 from score where score.s_id=student.s_id and score.c_id='01'
)
select stu1.s_name,count(1)
from student stu1
where exists(
select 1 from student stu2
where stu1.s_name=stu2.s_name and stu1.s_id!=stu2.s_id
)
group by stu1.s_name;
select stu1.s_name,count(1)
from student stu1 left semi join student stu2 on (stu1.s_name=stu2.s_name and stu1.s_id!=stu2.s_id)
group by stu1.s_name;
关于join中的on子句的官方文档说明,在hive2.2后on子句才是可以在on子句中实现更为复杂的表达式,如:不等值表达式(!=,<>,>)等 hive中在0.13版本后就支持某些where的子查询,但是where子查询中只支持(not)in或exists的子查询(在(not)in/exists子句中将子查询的结果作为常量)。同时由于hive中对子查询的支持度较低,有如下官方文档限制:
3. map-side join
map-side join:正如这名字一样,在map端就join连接,从而减少了不必要的数据从map端shuffle到reducer端,从而提高了效率,减少网络io的占用。
实现:先在setup方法(mapTask任务开始前会调用一次)中,通过分片信息找到小表,把小表的数据加载到内存中(Map,List)。然后再和map方法读取的大表的信息进行join.过滤掉不要的数据,从而提高查询效率。
4. count的优化
count的执行
1. 执行效果上:
- count(*)包括了所有的列,相当于行数,在统计结果的时候不会忽略null值
- count(1)包括了所有列,用1代表行,在统计结果的时候也不会忽略null值
- count(列名)只包括列名那一列,在统计结果时,会忽略null值
2.执行效率上:
- 列名为主键,count(列名)会比count(1)快
- 列名不为主键,count(1)会比count(列名)快
- 如果表中有多个列并且没有主键,count(1)的效率高于count(*)
- 如果有主键count(主键)效率是最高的
- 如果表中只有一个字段count(*)效率最高
5. 分区与分桶
随着系统运行时间越来越长,表的数据量越来越大,而hive查询如果还是通过全表查询来进行查询,效率是极低的。而且我们所需查询的数据是从特定的一部分数据查询即可,从而引出了分区partition的概念。即在建表时,将整个存储在不同子目录中,每个目录对应一个分区。查询时,我们就可以指定分区查询,避免了hive做全表扫描,提高效率。
分区的类型:
1. 静态分区:直接加载数据文件到指定分区
2. 动态分区:数据未知,根据分区值来确定需要创建的分区(加载数据insert into模式)
3. 混合分区:静态和动态都有
注意事项:
1.hive的分区使用的是表外字段,分区字段是一个伪例,并不一定来源与原数据内。但是分区字段可以做查询过滤。
2.一般不建议使用动态分区,因为动态分区会使用MapReduce进行查询数据,如果分区数据过多,导致namenode和resourcemanager的性能瓶颈。所以建议在使用动态分区前尽可能预知分区数量。
与MapReduce中的HashPartitioner的原理一模一样
其实简单来说就是,将数据平均的分在不同的“桶”里。分配规则是使用分桶字段的hash值对分桶的数量进行取模,通过分析余数来确定放入哪个桶中
分桶的主要意义:分桶表主要适合进行'数据的抽样'
注意:加载数据时:绝对不能使用load或者上传方式,而是需要类似与动态分区一样加载数据
如有问题欢迎及时提醒,一起讨论与学习!
|