hive 两个没有null指定的表左关联的结果有null_Hive的优化原则

原文链接:https://zhuanlan.zhihu.com/p/174469951

本篇将 Hive 的优化分成三个部分:

  • 第一部分是 SQL 通用语法优化,
  • 第二部分是针对 Hive 所具有的数据倾斜的优化,
  • 第三部分则介绍一些通用性的 Hive 参数设置优化。

一、语法优化

SQL 的语法优化本质上是如何用更少的计算资源干相同的活,基于此延伸出几条原则,这几条原则又拓展出对应的一些具体方法:

原则1:取更少的数

这条原则特别朴素,只要数据量少了运算的效率自然会提升,但如何能够取更少数的同时不影响结果呢?

1、不要用 select *

这条不多说了,一些宽表少则二三十,多则上百列,而实际绝大多数都是我们不需要的,在 select 时只挑选后续需要用到字段而不是 select *,那么运算时间会成倍减少。

2、谓词下推

谓词下推指:

将过滤表达式尽可能移动至靠近数据源的位置,以使真正执行时能直接跳过无关的数据。

简单来说就是把 where 语句尽可能挪到最底层的位置,在最底层就把不需要的数据都过滤掉,然后让真正需要的数据参与运算,而不是留到最后才进行过滤。

根据谓词下推的思想,可对下面的代码进行优化:

select t1.name, t2.age, t2.class, t2.income from t1 join t2 on t1.id = t2.id where t2.age > 18

优化后:

select t1.name, t2.age, t2.class, t2.income from t1 
join
(select id, age, class, income from t2 where id > 18) t2
on t1.id = t2.id

3、多用子查询

基于谓词下推的思想,我们还可以做进一步的优化,即多用子查询,上面的代码可进一步优化成如下样子:

select t1.name, t2.age, t2.class, t2.income from
(select id, name from t1) t1
join
(select id, age, class, income from t2 where age > 18) t2
on t1.id = t2.id

采用子查询后,尽管会增加 job 数但提前把数据完成了过滤,还提高了代码的可读性,尤其是当需要关联的表和条件成倍增加后,可读性将会非常重要。

4、子查询的去重

当子查询的表中所需的字段存在重复值,那么对这些字段提前进行去重再进行关联同样会提高运算效率。还是以上面的代码为例:

select t1.name, t2.age, t2.class, t2.income from
(select id, name from t1) t1
join
(select id, age, class, income from t2 where age > 18 group by id, age, class, income) t2
on t1.id = t2.id

至于为什么用 group by 而不是 distinct 去重会在数据倾斜部分进行解释。

5、过滤null值

当关联所用到的字段包含了太多 null 时,需要从业务的角度考虑这些为 null 的数据是否有存在的必要,如果不必要的话尽早过滤掉,避免影响关联的效率。

如果确实需要用到,则可用 rand() 把数据均匀分布在不同的 reduce 上,避免数据倾斜,详细可见第二部分,此处仅列出代码:

select 
n.*,
o.name
from
nullidtable n
full join
bigtable o
on nvl(n.id,rand())=o.id

原则2:不排序

SQL 中进行排序是要消耗计算资源的,在 Hive 中这种资源消耗会更加明显。子查询里不要排序这一点就不多说了,子查询中排序是毫无意义的,同时在最后的结果步也尽可能少排序,排序这需求完全可以通过交互查询的UI或把结果数据导出进行替代解决。当然,如果进行查询时没有UI系统,或者不方便把数据导出,或者你就是想即时看到数据的排序情况,就当这条建议不存在就好,但在子查询里排序仍然还是毫无意义的。

原则3:分步

该原则主要目的是把大数据集拆成小数据集来运行。

1、减少在 selec 时用 case when

有时出结果时需要用 case when 进行分类输出,如下面例子

select 
dt,
count(distinct case when id=1 then user_id else null end) as id_1_cnt,
count(distinct case when id=2 then user_id else null end) as id_2_cnt
from table_1
where dt between '20200511' and '20200915'
group by dt

但是实测发现 case when 的执行效率很低,当数据量太大的时候甚至会跑不出数,因此上面的代码可优化成如下形式:

select 
t1.dt,
t1.id_1_cnt,
t2.id_2_cnt
from
(select
dt,
count(distinct user_id) as id_1_cnt
from table_1
where dt between '20200511' and '20200915' and id=1
group by dt) t1
left join
(select
dt,
count(distinct user_id) as id_2_cnt
from table_1
where dt between '20200511' and '20200915' and id=2
group by dt) t2
on t1.dt=t2.dt

当数据量很大或者 select 时有太多的 case when,采用上面的方式其执行效率会提高 10 倍以上。

2、多用临时表

当需要建的表其逻辑非常复杂时,需要考虑用临时表的方式把中间逻辑分布执行,一来方便阅读、修改和维护,二来减少硬盘的开销(相较于建中间表的方式)。

3、where+union all

当需要根据某字段分类汇总时发现运行速度很慢甚至跑不出结果,那么有可能是因为某一类型的数据样本量过大造成数据倾斜,此时可考虑通过 where 过滤 + union all 合并的方法分步统计和汇总来处理该问题。

优化前:

select 
age,
count(distinct id) as id_cnt
from age_table
group by age

优化后:

select 
age,
count(distinct id) as id_cnt
from age_table
where age<35
group by age
union all
select
age,
count(distinct id) as id_cnt
from age_table
where age>=35
group by age

SQL 语句的优化方法贵精不贵多,牢记上述原则和方法在日常取数建表写 SQL 时大部分情况下就已经接近最优效率了。

二、数据倾斜

在展开数据倾斜的优化之前,需要先了解 Hive 所采用 MapReduce 的原理

9a939ab1b97e7eab5656e8f0a348e2b1.png

以上图为例,快速过一遍 MapReduce 的工作流程:

1、首先把需要处理的数据文件上传到 HDFS 上,然后这些数据会被分为好多个小的分片,然后每个分片对应一个 map 任务,推荐情况下分片的大小等于 block 块的大小。然后 map 的计算结果会暂存到一个内存缓冲区内,该缓冲区默认为 100M,等缓存的数据达到一个阈值的时候,默认情况下是 80%,然后会在磁盘创建一个文件,开始向文件里边写入数据。
2、map 任务的输入数据的格式是 key-value 对的形式,然后 map 在往内存缓冲区里写入数据的时候会根据 key 进行排序,同样溢写到磁盘的文件里的数据也是排好序的,最后 map 任务结束的时候可能会产生多个数据文件,然后把这些数据文件再根据归并排序合并成一个大的文件。
3、然后每个分片都会经过 map 任务后产生一个排好序的文件,同样文件的格式也是 key-value 对的形式,然后通过对 key 进行 hash 的方式把数据分配到不同的 reduce 里边去,这样对每个分片的数据进行 hash,再把每个分片分配过来的数据进行合并,合并过程中也是不断进行排序的。最后数据经过 reduce 任务的处理就产生了最后的输出。

简单来说,map 阶段负责不同节点上一部分数据的统计工作,reduce 阶段负责汇总聚合的工作。

有时一个 reduce 可以处理多个任务,但一些全局的工作只能让一个 reduce 负责,例如统计总行数、distinct去重等,此时就 reduce 就不能有多个实例并发执行,这就会造成其他 reduce 的任务已经执行完了,而负责全局的 reduce 还没执行完,这就是数据倾斜的本质,因此避免数据倾斜的核心在于均匀分配任务。

1、数据量大的时候用group by

当需要对数据进行去重时,在数据量较大的情况下可以选择用 group by 而不是 distinct,原理如下:

默认情况下,map 阶段同一 key 数据分发给一个 reduce,当一个 key 数据过大时就会发生数据倾斜了。但是并不是所有的聚合操作都只能在 reduce 完成,很多聚合操作也可以先在 map 进行部分聚合,最后在 reduce 端得出最终结果。

开启 Map 端聚合参数设置

(1)是否在 Map 端进行聚合,默认为 true

set hive.map.aggr = true;

(2)在 Map 端进行聚合操作的条目数目

set hive.groupby.mapaggr.checkinterval = 100000;

(3)有数据倾斜的时候进行负载均衡(默认是false)

set hive.groupby.skewindata = true;

当选项设定为 true,生成的查询计划会有两个MR Job。第一个MR Job中,Map 的输出结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个MR Job再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。

而与之相对应的,distinct 则只会用一个 reduce 来执行,造成数据量过大而让整体任务执行时间过长或无法完成。

但是需要注意的是,用 group by 来去重会额外增加一个子查询,只有当数据量很大的情况或任务执行中出现严重的数据倾斜,group by 去重后 count 才会比 count(distinct) 效率更高。

2、Mapjoin

如果不指定 MapJoin 或者不符合 MapJoin 的条件,那么 Hive 解析器会将 Join 操作转换成 Common Join,即:在 Reduce 阶段完成 join。容易发生数据倾斜。可以用 MapJoin 把小表全部加载到内存在 map 端进行 join,避免 reducer 处理。

(1)设置自动选择 Mapjoin

set hive.auto.convert.join = true; 默认为true

(2)大表小表的阈值设置(默认25M以下认为是小表):

set hive.mapjoin.smalltable.filesize=25000000;

数据倾斜的处理在 Hive 优化中是一个大课题,实际场景中所遇到的 Hive 任务执行过长或报错有80%都与数据倾斜有关,后续有机会的话可能专门写一篇针对解决数据倾斜的文章。

三、参数优化

该部分罗列了一些常用的 Hive 参数设置,并逐条做简单介绍

1、set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveFormat;(默认开启)

将多个小文件打包作为一个整体的 inputsplit,减少 map 任务数

2、set hive.merge.mapfiles=true;(默认值为真)

合并 map 端小文件的输出

3、set hive.auto.convert.join=true;

开启 mapjoin

4、set hive.mapjoin.smalltable.filesize=25000000; (默认25M)

设置 mapjoin 的开启阈值

5、set hive.optimize.skewjoin=true;

有数据倾斜的时候进行负载均衡

6、set hive.skewjoin.key=100000;

表示当记录条数超过100000时采用 skewjoin 操作

7、set hive.exec.parallel=true;

多个 join 多个 union all 优化,开启不同 stage 任务并行计算

8、set hive.exec.parallel.thread.number=16;(默认为8)

同一个 SQL 允许最大并行度

9、set hive.map.aggr=true;

group by 数据倾斜优化 设置在 map 端进行聚合

10、set hive.groupby.skewindata=true;

group by 数据倾斜优化

11、set hive.exec.mode.local.auto=true;

开启本地模式

12、set mapred.compress.map.output=true;

开启中间压缩

以上是 Hive 通用属性的设置,下面的参数主要目的是控制 map 和 reduce 的数量,需要依情况而设定:

13、set hive.merge.smallfiles.avgsize=16000000;

平均文件大小,是决定是否执行合并操作的阈值

14、set mapred.min.split.size.per.node=128000000;

低于 128M 就算小文件,数据在一个节点会合并,在多个不同的节点会把数据抓取过来进行合并

15、set mapred.min.split.size.per.rack=64000000;

每个机架处理的最小 split

16、set mapred.max.split.size=256000000;

决定每个 map 处理的最大的文件大小

17、set mapred.min.split.size=10000000;

决定每个 map 处理的最小的文件大小

18、set hive.merge.size.per.task=256000000;(默认值为256000000)

对 map 个数进行设置

19、set mapred.reduce.tasks=10;

设置 reduce 的数量

20、set hive.exec.reducers.bytes.per.reducer=536870912;(512M)

调整每个 reduce 处理数据量的大小

以上关于 map 和 reduce 的参数需要根据实际情况设置,具体的设置逻辑碍于篇幅所限就不展开了,如果有机会的话需要单独列一篇作详细介绍。

除了以上的优化方向外,还可以通过设置 Hive 的文件格式来提高效率,目前优化做得最好的文件格式就是 ORCfile,可以在建表时通过 stored as ORC 来调用。另外,可以根据实际工作需要把一些常用的统计汇总逻辑用中间表的形式存储起来,便于后续查询。

Hive 的优化是一个系统性的工作,本篇仅列一二,但是由于以后是 Spark 以及其他更优秀引擎的天下了,所以如果以后还要对 Hive 进行优化,那大概就是换一个语言吧(不是)。

如果觉得还有帮助的话,你的关注和转发是对我最大的支持,O(∩_∩)O:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/502972.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python数据分析兼职能挣钱吗_Python开发能从事数据分析吗

Python不仅是人工智能时代最佳的编程语言&#xff0c;同时也是数据分析、科学运算的首选编程语言。学习Python就业方向多&#xff0c;比如Web网站开发、人工智能等。Python数据分析师需要掌握哪些技能&#xff0c;从各大招聘网站对其的基本任职要求可以了解一二&#xff1a; 1、…

python中打开文件open_Python中打开文件的方式(With open)

1.读文件 要以读文件的模式打开一个文件对象&#xff0c;使用Python内置的open()函数&#xff0c;传入文件名和标 示符&#xff1a; f open( /Users/michael/test.txt, r ) 标示符’r’表示读&#xff0c;这样&#xff0c;我们就成功地打开了一个文件。 如果文件不存在&#x…

jdk 安装_Linux入门之Linux CentOS安装jdk

第一步&#xff1a;创建jdk安装目录(该/usr/local/src 目录是空的,最好把我们自己下载的放到这,容易区分)mkdir -p /usr/local/src/jdk第二步&#xff1a;查看之前是否安装rpm -qa | grep -i jdk若之前安装过jdk&#xff0c;下次安装一定把之前的删除干净第三步&#xff1a;命令…

asp点击按钮sql列求和_SQL 结构化查询语言

SQL特点SQL是大小写无关的&#xff0c;但一般的习俗是&#xff0c;关键字大写&#xff08;SELECT WHERE&#xff09;&#xff0c;用户自定义的小写&#xff0c;如表名。SQL如何注释&#xff0c; 两个 -- 开头&#xff0c;即为注释。SQL只用于关系型数据库&#xff0c;如MySQL&a…

获取两个圆的重合部分的经纬度_(2)万向节的装配和动画仿真:重合同轴心装配约束很常用...

前面的一篇文章中我们已经将万向节装配完成了一部分&#xff0c;还有一部分没有完成装配。前面的装配当中用到了重合&#xff0c;同轴心&#xff0c;相切的装配约束&#xff0c;这几个装配约束都是比较常用的大家一定要注意掌握。前面的话接下来的课程当中我们将会进行完整的装…

php无法连接mysql_php无法连接数据库

PHP无法连接数据库的解决办法总结&#xff1a;1、获取当前 mysql.default_socket、mysqli.default_socket、pdo_mysql.default_socket 配置信息建立一个 PHP 文件&#xff0c;显示 phpinfo()&#xff0c;用浏览器打开如图:在此页面&#xff0c;找到mysql.default_socket、mysql…

oracle 查看监听命令_linux下使用Oracle常用命令

进入Oracle用户1su - oracle以dba身份进入sql语句1sqlplus / as sysdba启动数据库相关命令启动数据库1startup启动监听(关闭监听的命令lsnrctl stop)&#xff0c;退出sql编写界面1lsnrctl start关闭数据库服务&#xff0c;在sql编写界面1shutdown immediate常看当前连接用户的信…

对飞行前请求的响应未通过访问控制检查:它没有http ok状态。_对不起,看完这篇HTTP,真的可以吊打面试官...

点击上方“码农沉思录”&#xff0c;选择“设为星标”优质文章&#xff0c;及时送达HTTP 内容协商什么是内容协商在 HTTP 中&#xff0c;内容协商是一种用于在同一 URL 上提供资源的不同表示形式的机制。内容协商机制是指客户端和服务器端就响应的资源内容进行交涉&#xff0c;…

mysql hma 分布式_mysql基础之mariadb集群双主(主主)架构

一、概念在企业中&#xff0c;数据库高可用一直是企业的重中之重&#xff0c;中小企业很多都是使用mysql主从方案&#xff0c;一主多从&#xff0c;读写分离等&#xff0c;但是单主存在单点故障&#xff0c;从库切换成主库需要作改动。因此&#xff0c;如果是双主或者多主&…

c++十六进制转十进制_一文帮你详细图解二进制、八进制、十进制、十六进制之间的转换...

1、背景(Contexts)之前使用SQL把十进制的整数转换为三十六进制&#xff0c;SQL代码请参考&#xff1a;SQL Server 进制转换函数&#xff0c;其实它是基于二、八、十、十六进制转换的计算公式的&#xff0c;进制之间的转换是很基础的知识&#xff0c;但是我发现网络上没有一篇能…

ceph存储原理_赠书 | Linux 开源存储全栈详解——从Ceph到容器存储

//留言点赞赠书我有书&#xff0c;你有故事么&#xff1f;留言说出你的存储故事留言点赞前两名&#xff0c;免费送此书截止日期12.27号12.30号公布名单//内容简介本书致力于帮助读者形成有关Linux开源存储世界的细致的拓扑&#xff0c;从存储硬件、Linux存储堆栈、存储加速、存…

mysql双主 绿色_mysql (双主,互主)

Master-Master(双主)1、测试环境Master/Slave Master1/Slave1IP 192.168.1.13 192.168.1.10为了保持干净的环境&#xff1a;两边服务器rm -rf /var/lib/mysql/*service mysqld restartIP:192.168.1.13IP:192.168.1.102、…

学习在UE中通过Omniverse实现对USD文件的Live-Sync(实时同步编辑)

目标 前一篇 学习了Omniverse的一些基础概念。本篇在了解这些概念的基础上&#xff0c;我想体验下Omniverse的一些具体的能力&#xff0c;特别是 Live-Sync (实时同步) 相关的能力。 本篇实践了使用Omniverse的力量在UE中建立USD文件的 Live-Sync 编辑。由于相关的知识我是从…

keras卷积处理rgb输入_CNN卷积神经网络模型搭建

前言前段时间尝试使用深度学习来识别评测过程中的图片&#xff0c;以减少人力成本。目前是在深度学习框架Keras(后端使用TensorFlow)下搭建了一个CNN卷积神经网络模型&#xff0c;下面就如何搭建一个最简单的数字图像识别模型做下介绍。模型的建立(1) 卷积层(convolution layer…

python中try命令_Python 异常处理 Python 基础教程 try..except

异常处理在之前的学习中我们一直没有接触过。 哦对&#xff0c;我们甚至还不知道怎么向程序输入一段字符串。那么我们在这里提供一个小例子。 在命令行中&#xff0c;我们输入 s raw_input(Enter something --> )好了&#xff0c;我们已经知道如何输入一个字符串了&#xf…

python分词_Python 结巴分词实现关键词抽取分析

1 简介 关键词抽取就是从文本里面把跟这篇文档意义最相关的一些词抽取出来。这个可以追溯到文献检索初期&#xff0c;当时还不支持全文搜索的时候&#xff0c;关键词就可以作为搜索这篇论文的词语。因此&#xff0c;目前依然可以在论文中看到关键词这一项。 除了这些&#xff0…

redis 如何 mysql_Redis 如何保持和 MySQL 数据一致

一、需求起因在高并发的业务场景下&#xff0c;数据库大多数情况都是用户并发访问最薄弱的环节。所以&#xff0c;就需要使用redis做一个缓冲操作&#xff0c;让请求先访问到redis&#xff0c;而不是直接访问MySQL等数据库。这个业务场景&#xff0c;主要是解决读数据从Redis缓…

iframe 跨域_【梯云纵】搞定前端跨域

韦陀掌法,难陀时间善恶&#xff1b;梯云纵,难纵过乱世纷扰。现在开始写代码o(╯□╰)o什么是跨域1.跨域的定义广义的跨域是指一个域下对的文档或者脚本试图去请求另外一个域下的资源。a链接、重定向、表单提交、、、等标签background:url()、font-face()ajax 跨域请求……狭义的…

java中exception_Java中的异常 Exceptions

1. 概念exception是“exceptional event”的缩写&#xff0c;是指执行程序中发生的事件&#xff0c;破坏了程序的正常执行流程。Java 异常处理机制使程序更加健壮易于调试&#xff0c;它可以告诉程序员三个问题&#xff1a;错误的类型、位置、原因&#xff0c;帮助程序员解决错…

python异步asy_Python 异步编程之asyncio【转载】

一、协程的认识 协程&#xff08;Coroutine&#xff09;&#xff0c;也可以被称为微线程&#xff0c;是一种用户态内的上下文切换技术。 简而言之&#xff0c;其实就是通过一个线程实现代码块相互切换执行。例如&#xff1a;deffunc1():print(1) ...print(2)deffunc2():print(3…