HQL底层原理及优化:1 干预SQL的运行方式 之1.2通过Hint对计算引擎执行过程进行干预

Hint,意为提示。

1 Hint简介

本小节参考自文章Oracle hint详解中的一部分,感谢原作者的分享。

Hive的底层计算引擎MapReduce,分Mapper阶段和Reducer阶段。若有极小的表(<25M)参与join,可使用MapJoin Hint关键字在Mapper阶段即进行连接,进而避免reducer操作。

一般情况不建议使用MapJoin 关键字,因为主观认为的小表,可能突然变成超大的表,进而成为灾难。

所以,Hive0.7之前,需要使用hint提示 /*+ mapjoin(table) */才会执行MapJoin,否则执行Common Join,但在0.7版本之后,默认自动会转换Map Join,由参数hive.auto.convert.join来控制,默认为true.
假设a表为一张大表,b为小表,并且hive.auto.convert.join=true,那么Hive在执行时候会自动转化为MapJoin。

1.1 为什么引入Hint?

Hint是Oracle数据库中很有特色的一个功能,是很多DBA优化中经常采用的一个手段。那为什么Oracle会考虑引入优化器呢?基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻DBA的负担。

但有时它也聪明反被聪明误选择了很差的执行计划,使某个语句的执行变得奇慢无比。此时就需要DBA进行人为的干预,告诉优化器使用指定的存取路径或连接类型生成执行计划,从而使语句高效地运行。Hint就是Oracle提供的一种机制,用来告诉优化器按照告诉它的方式生成执行计划。

1.2 不要过分依赖Hint

当遇到SQL执行计划不好的情况,应优先考虑统计信息等问题,而不是直接加Hint了事。如果统计信息无误,应该考虑物理结构是否合理,即没有合适的索引。只有在最后仍然不能SQL按优化的执行计划执行时,才考虑Hint。

毕竟使用Hint,需要应用系统修改代码,Hint只能解决一条SQL的问题,并且由于数据分布的变化或其他原因(如索引更名)等,会导致SQL再次出现性能问题

1.3 Hint的弊端

Hint是比较"暴力"的一种解决方式,不是很优雅。需要开发人员手工修改代码。
Hint不会去适应新的变化。比如数据结构、数据规模发生了重大变化,但使用Hint的语句是感知变化并产生更优的执行计划。
Hint随着数据库版本的变化,可能会有一些差异、甚至废弃的情况。此时,语句本身是无感知的,必须人工测试并修正。

1.4 Hint与注释关系

提示是Oracle为了不破坏和其他数据库引擎之间对SQL语句的兼容性而提供的一种扩展功能。Oracle决定把提示作为一种特殊的注释来添加。它的特殊性表现在提示必须紧跟着DELETE、INSERT、UPDATE或MERGE关键字

换句话说,提示不能像普通注释那样在SQL语句中随处添加。且在注释分隔符(/*)之后的第一个字符必须是加号。在后面的用法部分,会详细说明。

1.5 语法

  • DELETE、INSERT、SELECT和UPDATE是标识一个语句块开始的关键字,包含提示的注释只能出现在这些关键字的后面,否则提示无效。
  • "+“号表示该注释是一个提示,该加号必须立即跟在”/*"的后面,中间不能有空格。
  • hint是下面介绍的具体提示之一,如果包含多个提示,则每个提示之间需要用一个或多个空格隔开。
  • text是其它说明hint的注释性文本

在Oracle中的Hint有许多种,Hive中的Hint尚未广泛了解,以后再补充。

2 使用MapJoin Hint的SQL

2.1 实现参数

MapJoin通常用于一个很小的表和一个大表进行join的场景,具体小表有多小,由参数 hive.mapjoin.smalltable.filesize来决定,该参数表示小表的总大小,默认值为25000000字节,即25M.
Hive0.7之前,需要使用hint提示* /+ mapjoin(table) */才会执行MapJoin,否则执行Common Join,但在0.7版本之后,默认自动会转换Map Join,由数hive.auto.convert.join来控制,默认为true.
仍然以9.1中的HQL来说吧,假设a表为一张大表,b为小表,并且hive.auto.convert.join=true,那么Hive在执行时候会自动转化为MapJoin。

2.2 底层执行流程

在这里插入图片描述
如上图中的流程,首先是Task A,它是一个Local Task(在客户端本地执行的Task),负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中,该HashTable的数据结构可以抽象为:
|key| value|
| 1 | 26 |
| 2 | 34 |
在这里插入图片描述
在这里插入图片描述
图中红框圈出了执行Local Task的信息。

  • 接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。
  • 由于MapJoin没有Reduce,所以由Map直接输出结果文件,有多少个Map Task,就有多少个结果文件

2.3 测试

1、两表关联:

select e.empno,e.ename,e.deptno,d.deptno,d.dname 
from emp e join dept d 
on e.deptno = d.deptno;

条件:emp表数据为1000条,dept表数据为100条;
说明:执行时间mapjoin会通过元数据(metadata)进行查找,发现是否存在小表(根据hive.mpajoin.samlltable.filesize参数设置,判断是否为小表。此参数默认25M)。
存在小表时将先行进行小表加载到内存中,即dept表,如上HQL语句将dept表加载至内存中,最后再用emp表中数据一条一条与内存中数据进行关联查询。

2、多表关联

select e.empno,e.ename,e.deptno,d.deptno,d.dname 
from emp e join dept d join emp_partition c 
on e.deptno = d.deptno and e.empno = c.empno;

条件:emp表数据为1000条,dept表数据为100条,emp_partition表数据为500条。
说明:执行时间mapjoin会通过元数据(metadata)进行查找,发现是否存在小表(根据hive.mpajoin.samlltable.filesize参数设置,判断是否为小表。此参数默认25M)。
存在小表时将先行进行小表加载到内存中,即dept、emp_partition表,如上HQL语句将dept表加载至内存中,最后再用emp表中数据一条一条与内存中数据进行关联查询。
注:以上可以对照SQL的执行计划或执行日志更详细,后续补充相关截图及说明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张之海

若有帮助,客官打赏一分吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值