Hive SQL优化思路

简介: Hive的优化主要分为:配置优化、SQL语句优化、任务优化等方案。其中在开发过程中主要涉及到的可能是SQL优化这块。

Hive的优化主要分为:配置优化、SQL语句优化、任务优化等方案。其中在开发过程中主要涉及到的可能是SQL优化这块。


优化的核心思想是:


  • 减少数据量(例如分区、列剪裁)
  • 避免数据倾斜(例如加参数、Key打散)
  • 避免全表扫描(例如on添加加上分区等)
  • 减少job数(例如相同的on条件的join放在一起作为一个任务)


HQL语句优化



1. 使用分区剪裁、列剪裁


在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤。


select a.*  
from a  
left join b on  a.uid = b.uid  
where a.ds='2020-08-10'  
and b.ds='2020-08-10'


上面这个SQL主要犯了两个错误:


  1. 副表(上方b表)的where条件写在join后面,会导致先全表关联在过滤分区。


注:虽然a表的where条件也写在join后面,但是a表会进行谓词下推,也就是先执行where条件,再执行join,但是b表不会进行谓词下推!


  1. on的条件没有过滤null值的情况,如果两个数据表存在大批量null值的情况,会造成数据倾斜。


正确写法:


select a.*  
from a  
left join b on (d.uid is not null and a.uid = b.uid and b.ds='2020-08-10') 
where a.ds='2020-08-10'


如果null值也是需要的,那么需要在条件上转换,或者单独拿出来


select a.*  
from a  
left join b on (a.uid is not null and a.uid = b.uid and b.ds='2020-08-10')  
where a.ds='2020-08-10'  
union all  
select a.* from a where a.uid is null


或者:


select a.*  
from a  
left join b on   
case when a.uid is null then concat("test",RAND()) else a.uid end = b.uid and b.ds='2020-08-10'  
where a.ds='2020-08-10'


或者(子查询):


select a.*  
from a  
left join   
(select uid from where ds = '2020-08-10' and uid is not null) b on a.uid = b.uid 
where a.uid is not null  
and a.ds='2020-08-10'


2. 尽量不要用COUNT DISTINCT


因为COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换,虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。


select count(distinct uid)  
from test  
where ds='2020-08-10' and uid is not null


转换为:


select count(a.uid)  
from   
(select uid 
 from test 
 where uid is not null and ds = '2020-08-10' 
 group by uid
) a


3. 使用with as


拖慢Hive查询效率除了join产生的shuffle以外,还有一个就是子查询,在SQL语句里面尽量减少子查询。with as是将语句中用到的子查询事先提取出来(类似临时表),使整个查询当中的所有模块都可以调用该查询结果。使用with as可以避免Hive对不同部分的相同子查询进行重复计算。


select a.*  
from  a  
left join b on  a.uid = b.uid  
where a.ds='2020-08-10'  
and b.ds='2020-08-10'


可以转化为:


with test1 as 
(
select uid  
from b  
where ds = '2020-08-10' and uid is not null  
)  
select a.*  
from a  
left join test1 on a.uid = test1.uid  
where a.ds='2020-08-10' and a.uid is not null


4. 大小表的join


写有Join操作的查询语句时有一条原则:应该将条目少的表/子查询放在Join操作符的左边。原因是在Join操作的Reduce阶段,位于Join操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生OOM错误的几率。但新版的hive已经对小表JOIN大表和大表JOIN小表进行了优化。小表放在左边和右边已经没有明显区别。不过在做join的过程中通过小表在前可以适当的减少数据量,提高效率。


5. 数据倾斜


数据倾斜的原理都知道,就是某一个或几个key占据了整个数据的90%,这样整个任务的效率都会被这个key的处理拖慢,同时也可能会因为相同的key会聚合到一起造成内存溢出。


数据倾斜只会发生在shuffle过程中。这里给大家罗列一些常用的并且可能会触发shuffle操作的算子:distinct、 groupByKey、reduceByKey、aggregateByKey、join、cogroup、repartition等。出现数据倾斜时,可能就是你的代码中使用了这些算子中的某一个所导致的。


hive的数据倾斜一般的处理方案:


常见的做法,通过参数调优:


set hive.map.aggr=true;  
set hive.groupby.skewindata = ture;


当选项设定为true时,生成的查询计划有两个MapReduce任务。


在第一个MapReduce中,map的输出结果集合会随机分布到reduce中,每个reduce做部分聚合操作,并输出结果。


这样处理的结果是,相同的Group By Key有可能分发到不同的reduce中,从而达到负载均衡的目的;


第二个MapReduce任务再根据预处理的数据结果按照Group By Key分布到reduce中(这个过程可以保证相同的Group By Key分布到同一个reduce中),最后完成最终的聚合操作。


但是这个处理方案对于我们来说是个黑盒,无法把控。


一般处理方案是将对应的key值打散即可。


例如:


select a.*  
from a  
left join b on  a.uid = b.uid  
where a.ds='2020-08-10'  
and b.ds='2020-08-10'


如果有90%的key都是null,这样不可避免的出现数据倾斜。


select a.uid  
from test1 as a  
join(  
   select case when uid is null then cast(rand(1000000) as int)  
   else uid  
   from test2 where ds='2020-08-10') b   
on a.uid = b.uid  
where a.ds='2020-08-10'


当然这种只是理论上的处理方案。


正常的方案是null进行过滤,但是日常情况下不是这种特殊的key。


那么在日常需求的情况下如何处理这种数据倾斜的情况呢:


  1. sample采样,获取哪些集中的key;
  2. 将集中的key按照一定规则添加随机数;
  3. 进行join,由于打散了,所以数据倾斜避免了;
  4. 在处理结果中对之前的添加的随机数进行切分,变成原始的数据。


当然这些优化都是针对SQL本身的优化,还有一些是通过参数设置去调整的,这里面就不再详细描述了。


但是优化的核心思想都差不多:


  1. 减少数据量
  2. 避免数据倾斜
  3. 减少JOB数
  4. 虚核心点:根据业务逻辑对业务实现的整体进行优化;
  5. 虚解决方案:采用presto、impala等专门的查询引擎,采用spark计算引擎替换MR/TEZ
相关文章
|
2月前
|
SQL
慢sql治理问题之 Task 数量分布不均的问题你们是如何优化的
慢sql治理问题之 Task 数量分布不均的问题你们是如何优化的
慢sql治理问题之 Task 数量分布不均的问题你们是如何优化的
|
2月前
|
SQL 存储 分布式计算
插入Hive表数据SQL
【8月更文挑战第10天】
|
2月前
|
SQL 物联网 数据处理
"颠覆传统,Hive SQL与Flink激情碰撞!解锁流批一体数据处理新纪元,让数据决策力瞬间爆表,你准备好了吗?"
【8月更文挑战第9天】数据时代,实时性和准确性至关重要。传统上,批处理与流处理各司其职,但Apache Flink打破了这一界限,尤其Flink与Hive SQL的结合,开创了流批一体的数据处理新时代。这不仅简化了数据处理流程,还极大提升了效率和灵活性。例如,通过Flink SQL,可以轻松实现流数据与批数据的融合分析,无需在两者间切换。这种融合不仅降低了技术门槛,还为企业提供了更强大的数据支持,无论是在金融、电商还是物联网领域,都将发挥巨大作用。
44 6
|
2月前
|
Java XML Maven
跨越时代的飞跃:Struts 2 升级秘籍——从旧版本无缝迁移到最新版,焕发应用新生!
【8月更文挑战第31天】随着软件技术的发展,Struts 2 框架也在不断更新。本文通过具体案例指导开发者如何从旧版平滑升级到 Struts 2.6.x。首先更新 `pom.xml` 中的依赖版本,并执行 `mvn clean install`。接着检查 `struts.xml` 配置,确保符合新版本要求,调整包扫描器等设置。审查 Action 类及其注解,检查配置文件中的弃用项及插件。更新自定义拦截器实现,并验证日志配置。最后,通过一系列测试确保升级后的系统正常运行。通过这些步骤,可以顺利完成 Struts 2 的版本升级,提升应用的安全性和性能。
94 0
|
2月前
|
SQL 存储 数据库
|
2月前
|
SQL 数据管理 关系型数据库
SQL与云计算:利用云数据库服务实现高效数据管理——探索云端SQL应用、性能优化、安全性与成本效益,为企业数字化转型提供全方位支持
【8月更文挑战第31天】在数字化转型中,企业对高效数据管理的需求日益增长。传统本地数据库存在局限,而云数据库服务凭借自动扩展、高可用性和按需付费等优势,成为现代数据管理的新选择。本文探讨如何利用SQL和云数据库服务(如Amazon RDS、Google Cloud SQL和Azure SQL Database)实现高效的数据管理。通过示例和最佳实践,展示SQL在云端的应用、性能优化、安全性及成本效益,助力企业提升竞争力。
45 0
|
2月前
|
SQL 关系型数据库 MySQL
SQL性能调优的神奇之处:如何用优化技巧让你的数据库查询飞起来,实现秒级响应?
【8月更文挑战第31天】在现代软件开发中,数据库性能至关重要。本文通过一个实战案例,展示了从慢查询到秒级响应的全过程。通过对查询的详细分析与优化,包括创建索引、改进查询语句及数据类型选择等措施,最终显著提升了性能。文章还提供了示例代码及最佳实践建议,帮助读者掌握SQL性能调优的核心技巧。
46 0
|
2月前
|
SQL 关系型数据库 MySQL
SQL索引构建与优化的神奇之处:如何用高效索引让你的数据检索飞起来?
【8月更文挑战第31天】在现代软件开发中,数据库索引对于提升查询性能至关重要。本文详细介绍了SQL索引的概念、构建方法及优化技巧,包括避免不必要的索引、使用复合索引等策略,并提供了实用的示例代码,如 `CREATE INDEX index_name ON table_name (column_name, another_column_name);`。通过遵循这些最佳实践,如了解查询模式和定期维护索引,可以大幅提高数据检索效率,从而增强应用程序的整体性能。
78 0
|
2月前
|
SQL 关系型数据库 MySQL
OceanBase 的 SQL 兼容性与优化
【8月更文第31天】随着分布式计算的发展,越来越多的企业开始采用分布式数据库来满足其大规模数据存储和处理的需求。OceanBase 作为一款高性能的分布式关系数据库,其设计旨在为用户提供与传统单机数据库类似的 SQL 查询体验,同时保持高可用性和水平扩展能力。本文将深入探讨 OceanBase 的 SQL 引擎特性、兼容性问题,并提供一些针对特定查询进行优化的方法和代码示例。
111 0
下一篇
无影云桌面