经常看到一些Hive优化的建议中说当小表与大表做关联时,把小表写在前面,这样可以使Hive的关联速度更快,提到的原因都是说因为小表可以先放到内存中,然后大表的每条记录再去内存中检测,最终完成关联查询。这样的原因看似合理,但是仔细推敲,又站不住脚跟。
多小的表算小表?如果所谓的小表在内存中放不下怎么办?我用2个只有几条记录的表做关联查询,这应该算是小表了,在查看reduce的执行日志时依然是有写磁盘的操作的。实际上reduce在接收全部map的输出后一定会有一个排序所有键值对并合并写入磁盘文件的操作。写入磁盘(spill)有可能是多次的,因此有可能会生成多个临时文件,但是最终都要合并成一个文件,即最终每一个reduce都只处理一个文件。
我做了一个实验,用1条记录的表和3亿多条记录的表做join,无论小表是放在join的前面还是join的后面,执行的时间几乎都是相同的。再去看reduce的执行日志,1条记录的表在join前或者join后两次查询的reduce日志几乎也是一摸一样的。如果按照上面的说法把join左侧的表放内存等待join右侧的表到内存中去检测,那么当3亿多条记录的表放在join左侧时,内存肯定是无法容下这么多记录的,势必要进行写磁盘的操作,那它的执行时间应该会比小表在join前时长很多才对,但事实并不是这样,也就说明了上面说到的原因并不合理。
事实上“把小表放在前面做关联可以提高效率”这种说法是错误的。正确的说法应该是“把重复关联键少的表放在join前面做关联可以提高join的效率。”
分析一下Hive对于两表关联在底层是如何实现的。因为不论多复杂的Hive查询,最终都要转化成mapreduce的JOB去执行,因此Hive对于关联的实现应该和mapreduce对于关联的实现类似。而mapreduce对于关联的实现,简单来说,是把关联键和标记是在join左边还是右边的标识位作为组合键(key),把一条记录以及标记是在join左边还是右边的标识位组合起来作为值(value)。在reduce的shuffle阶段,按照组合键的关联键进行主排序,当关联键相同时,再按照标识位进行辅助排序。而在分区段时,只用关联键中的关联键进行分区段,这样关联键相同的记录就会放在同一个value list中,同时保证了join左边的表的记录在value list的前面,而join右边的表的记录在value list的后面。
例如A join B ON (A.id = b.id) ,假设A表和B表都有1条id = 3的记录,那么A表这条记录的组合键是(3,0),B表这条记录的组合键是(3,1)。排序时可以保证A表的记录在B表的记录的前面。而在reduce做处理时,把id=3的放在同一个value list中,形成 key = 3,value list = [A表id=3的记录,B表id=3的记录]
接下来我们再来看当两个表做关联时reduce做了什么。Reduce会一起处理id相同的所有记录。我们把value list用数组来表示。
1) Reduce先读取第一条记录v[0],如果发现v[0]是B表的记录,那说明没有A表的记录,最终不会关联输出,因此不用再继续处理这个id了,读取v[0]用了1次读取操作。
2) 如果发现v[0]到v[length-1]全部是A表的记录,那说明没有B表的记录,同样最终不会关联输出,但是这里注意,已经对value做了length次的读取操作。
3) 例如A表id=3有1条记录,B表id=3有10条记录。首先读取v[0]发现是A表的记录,用了1次读取操作。然后再读取v[1]发现是B表的操作,这时v[0]和v[1]可以直接关联输出了,累计用了2次操作。这时候reduce已经知道从v[1]开始后面都是B 表的记录了,因此可以直接用v[0]依次和v[2],v[3]……v[10]做关联操作并输出,累计用了11次操作。
4) 换过来,假设A表id=3有10条记录,B表id=3有1条记录。首先读取v[0]发现是A表的记录,用了1次读取操作。然后再读取v[1]发现依然是A表的记录,累计用了2次读取操作。以此类推,读取v[9]时发现还是A表的记录,累计用了10次读取操作。然后读取最后1条记录v[10]发现是B表的记录,可以将v[0]和v[10]进行关联输出,累计用了11次操作。接下来可以直接把v[1]~v[9]分别与v[10]进行关联输出,累计用了20次操作。
5) 再复杂一点,假设A表id=3有2条记录,B表id=3有5条记录。首先读取v[0]发现是A表的记录,用了1次读取操作。然后再读取v[1]发现依然是A表的记录,累计用了2次读取操作。然后读取v[2]发现是B表的记录,此时v[0]和v[2]可以直接关联输出,累计用了3次操作。接下来v[0]可以依次和v[3]~v[6]进行关联输出,累计用了7次操作。接下来v[1]再依次和v[2]~v[6]进行关联输出,累计用了12次操作。
6) 把5的例子调过来,假设A表id=3有5条记录,B表id=3有2条记录。先读取v[0]发现是A表的记录,用了1次读取操作。然后再读取v[1]发现依然是A表的记录,累计用了2次读取操作。以此类推,读取到v[4]发现依然是A表的记录,累计用了5次读取操作。接下来读取v[5],发现是B表的记录,此时v[0]和v[5]可以直接关联输出,累计用了6次操作。然后v[0]和v[6]进行关联输出,累计用了7次操作。然后v[1]分别与v[5]、v[6]关联输出,累计用了9次操作。V[2] 分别与v[5]、v[6]关联输出,累计用了11次操作。以此类推,最后v[4] 分别与v[5]、v[6]关联输出,累计用了15次操作。
7) 额外提一下,当reduce检测A表的记录时,还要记录A表同一个key的记录的条数,当发现同一个key的记录个数超过hive.skewjoin.key的值(默认为1000000)时,会在reduce的日志中打印出该key,并标记为倾斜的关联键。
最终得出的结论是:写在关联左侧的表每有1条重复的关联键时底层就会多1次运算处理。
假设A表有一千万个id,平均每个id有3条重复值,那么把A表放在前面做关联就会多做三千万次的运算处理,这时候谁写在前谁写在后就看出性能的差别来了。
相关推荐
3. **数据倾斜**:在处理小表与大表关联查询时,如果小表中的键值分布不均匀,可能导致数据倾斜,从而影响查询效率。因此,选择合理的连接键至关重要。 4. **缓存机制**:Hive支持将小表缓存在内存中,如使用`cache...
这些设置能够帮助确保在使用map join时,内存中的哈希表能高效地存储和快速地进行数据关联操作。 对于ORC文件格式,还需要了解其高级设置选项。比如,在创建Hive表时可以指定压缩算法,例如使用Zlib压缩。除此之外...
总的来说,理解和熟练运用LEFT JOIN、LEFT SEMI JOIN以及EXISTS子句是Hive SQL查询中的关键技能,它们在大数据分析中扮演着重要角色,帮助用户从海量数据中提取有价值的信息。根据实际需求选择合适的连接类型,能够...
Hive性能调优是一个复杂但关键的环节,涉及对Hive的参数配置以及针对应用程序的设计与开发进行优化。Hive是一个数据仓库基础工具,用于将结构化数据映射成数据库表,并通过HiveQL(简称HQL)查询语言执行数据处理...
通过对分区裁剪、列裁剪、多表关联、多表插入、左半连接以及存储格式和压缩策略的合理应用,可以显著提升Hive在大数据处理中的性能和效率。这些优化技巧不仅适用于特定的场景,而且可以灵活组合,以应对不同规模和...
该参数决定了是否根据输入小表的大小,自动将Reduce端的Common Join转化为Map Join,从而加快大表关联小表的Join速度。如果设置为true,则Hive将自动将Reduce端的Common Join转化为Map Join,默认值为false。 5. ...
在大数据处理领域,Hive作为一个基于Hadoop的数据仓库工具,被广泛用于数据分析和查询。针对Hive的性能优化,可以从多个角度入手,特别是在处理复杂的Join操作时。以下是根据标题、描述以及部分内容提炼出的关键知识...
2. **分区与桶**: 分区用于将大表划分为更小、更易管理的部分,桶则是对数据进行哈希划分,有助于提高JOIN操作的效率。 3. **存储格式**: Hive支持多种存储格式,如TextFile、SequenceFile、Parquet和ORC,不同的...
小表与大表关联也容易导致数据倾斜问题。解决方法是: * 使用MapJoin:set hive.auto.convert.join = true; * 设置小表刷入内存中的大小:set hive.mapjoin.smalltable.filesize = 2500000; * 设置最大Reduce个数:...
- **8.8 Join中处理null值的语义区别**:Hive处理NULL值的方式可能与传统SQL不同。 #### 九、优化与技巧 - **9.1 全排序**:对于大规模数据集进行全排序可能会导致性能问题。 - **9.2 怎样做笛卡尔积**:在特定...
假设日志数据中的`user_id`字段存在缺失情况,当尝试将其与用户表关联时,可能会出现数据倾斜。为解决此问题,可以通过以下两种方法之一: - 方法1:仅对非空的`user_id`进行关联操作,并将空值的记录单独处理。 ...
#### 四、Hive大表Join小表的优化方法 1. **小表前置**: - **方法**:将小表放在Join操作的前面。 - **效果**:Hive能够将小表缓存到内存中,从而提高Join操作的效率。 #### 五、Hive中各种Join类型 1. **内...
Hive是基于Hadoop的数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供SQL-like的查询语言(HQL)进行数据操作,适合大规模数据的离线分析。而HBase则是一个分布式、版本化、基于列族的NoSQL数据库,...
Hive是Apache Hadoop生态系统中的一个数据仓库工具,它允许用户使用SQL-like的语言(HQL,Hive Query Language)对大规模数据进行分析处理。Hive的主要设计目标是将复杂的MapReduce编程任务转换为简单的SQL查询,...
Hive编程实践涵盖了创建表、加载数据、编写HiveQL语句进行查询、聚合、JOIN操作,以及使用分区和桶优化查询性能等。 总结来说,Hive作为大数据处理的重要工具,通过与Hadoop生态系统的紧密协作,为企业提供了高效、...
利用JOIN操作可以关联不同表,获取更丰富的分析结果。 5. **数据统计与聚合**:在电商场景中,我们可能需要计算最畅销商品、最高销售额日、用户购买模式等。Hive提供了COUNT、SUM、AVG、MAX、MIN等聚合函数,以及...
虽然提供的文件名似乎与Hive直接关联不大,但在实际项目中,Hive可能与各种硬件和软件平台结合使用,例如在物联网设备的数据分析中。理解Hive的基础知识和其在大数据处理中的作用对于任何涉及Hadoop生态系统的开发和...
如果用户学历信息与其他表关联,如用户行为数据,那么JOIN操作是必不可少的。理解不同类型的JOIN(如INNER JOIN、LEFT JOIN、RIGHT JOIN等)及其性能影响是优化查询的关键。 9. **数据倾斜问题**: 当数据分布...