Join优化操作
思考: 在执行Join的SQL的时候, SQL会被翻译为MR, 思考, 翻译后MR默认是如何进行JOIN操作的呢?
思考: 这种reduce端Join操作, 存在那些弊端呢?
1- 可能会存在数据倾斜的问题 (某几个reduce接收数据量远远大于其他的reduce接收数据量)
2- 所有的数据处理的操作, 全部都压在reduce中进行处理, 而reduce数量相比Map来说少的多,导致整个reduce压力比较大
思考: 如何提升Join的效率呢? 思路: 能否不让reduce做这个聚合处理的事情, 将这项工作尝试交给mapTask
1 Map Join
Map Join: 每一个mapTask在读取数据的时候, 每读取一条数据, 就会和内存中班级表数据进行匹配, 如果能匹配的上, 将匹配上数据合并在一起, 输出即可
好处: 将原有reduce join 问题全部都可以解决
弊端:
1- 比较消耗内存
2- 要求整个 Join 中, 必须的都有一个小表, 否则无法放入到内存中
仅适用于: 小表 join 大表 | 大表 join 小表
在老版本(1.x以下)中, 需要将小表放置在前面, 大表放置在后面, 在新版本中, 无所谓
建议, 如果明确知道那些表示小表, 可以优先将这些表, 放置在最前面
如何使用呢?
-- map join
set hive.auto.convert.join=true; -- 开启 map join的支持 默认值为True
set hive.mapjoin.smalltable.filesize= 25000000; --设置 小表的文件大小(23.84m)
set hive.auto.convert.join.noconditionaltask.size=20971520; -- 设置 join任务数据量
如果不满足条件, HIVE会自动使用 reduce join 操作
2 Bucket Map Join
-
适用场景: 中型表 和 大表 join:
-
方案一: 如果中型表能对数据进行提前过滤, 尽量提前过滤, 过滤后, 有可能满足了Map Join 条件 (并不一定可用)
-
方案二: Bucket Map Join
-
-- bucket map join
set hive.optimize.bucketmapjoin; -- 默认false
/*
1- Join两个表必须是分桶表
2- 开启 Bucket Map Join 支持: set hive.optimize.bucketmapjoin = true;
3- 一个表的分桶数量是另一个表的分桶数量的整倍数
4- 分桶列 必须 是 join的ON条件的列
5- 必须建立在Map Join场景中(中型表是小表的3倍, 此时分至少3个桶)
*/
3 SMB Join
-
适用场景: 大表 和 大表 join
-
解决方案: SMB Join ( sort merge bucket map join)
-- 使用条件:
-- 1- 两个表必须都是分桶表
-- 2- 开启 SMB Join 支持:
set hive.auto.convert.sortmerge.join; -- 默认false
set hive.optimize.bucketmapjoin.sortedmerge ;-- 默认false
set hive.auto.convert.sortmerge.join.noconditionaltask;-- Hive 0.13.0默认开启
-- 3- 两个表的分桶的数量是一致的
-- 4- 分桶列 必须是 join的 on条件的列, 同时必须保证按照分桶列进行排序操作
-- 开启强制排序
set hive.enforce.sorting; -- hive2.x移除 默认true
-- 在建分桶表使用: 必须使用sorted by()
-- 5- 应用在Bucket Map Join 场景中
-- 开启 bucket map join
set hive.optimize.bucketmapjoin ; --默认false
一般来说:
事实表 + 低基数的维度表 进行关联: Map Join 优化
事实表 + 高基数的维度表 进行关联: Bucket Map Join 优化
事实表 + 事实表 进行关联: SMB Join 优化(相对使用最少, 因为条件过于苛刻, 而且对资源消耗过大, 如果资源不够, 运行效率低于原始Join方案)