hiveSql调优

news2024/12/29 11:59:41

一、hiveSQL执行顺序

from … where … mapjoin … on … select(筛选有用字段) … group by ||… join … on … select(筛选输出字段) … having … distinct … order by … limit … union/union all

|| 前是map阶段执行,后的reduce阶段执行
以如下hql为例:

select
  sum(b.order_amount) sum_amount,
  count(a.userkey) count_user
from user_info a
left join user_order b on a.idno=b.idno
where a.idno > '112233'
group by a.idno
having count_user > 1
limit 10;

hql执行顺序如下:

Map 阶段:
1、执行 from,进行表的查找与加载,注意要join的表也要加载进来(MapJoin除外);
2、执行 where,注意: sql 语句中 left join 写在 where 之前的,但是实际执行先执行 where 操作,因为 Hive 会对语句进行优化,如果符合谓词下推规则,将进行谓词下推;
3、如果join的是小表,可以执行 Map join 操作,按照 key 进行表的关联;
4、执行输出列的操作,注意: select 后面只有两个字段(order_amount,userkey),此时 Hive 是否只输出这两个字段呢,当然不是,因为 group by 的是 idno,如果只输出 select 的两个字段,后面 group by 将没有办法对 idno 进行分组,所以此时输出的字段有三个:idno,order_amount,userkey,所以这个select的作用是筛选出需要用到的字段,所以我们在写hql时最好不要用select *;
5、执行 map 端的 group by,此时的分组方式采用的是哈希分组,按照 idno 分组,进行 order_amount 的 sum 操作和 userkey 的 count 操作,最后按照 idno 进行排序(group by 默认会附带排序操作);
Reduce 阶段:
1、执行 reduce 端的 group by,此时的分组方式采用的是合并分组,对 map 端发来的数据按照 idno 进行分组合并,同时进行聚合操作 sum(order_amount)和 count(userkey);
2、执行 select,此时输出的就只有 select 的两个字段:sum(order_amount) as sum_amount,count(userkey) as count_user;
3、执行 having,此时才开始执行 group by 后的 having 操作,对 count_user 进行过滤,注意:因为上一步输出的只有 select 的两个字段了,所以 having 的过滤字段只能是这两个字段;
4、执行 limit,限制输出的行数为 10。

二、HiveSql数据转化过程

以下面sql为例:

hive> SELECT * FROM logs;
OK
a   苹果  5
a   橙子  3
b   烧鸡  1

hive> SELECT * FROM users;
OK
a   23
b   21

hive> SELECT a.uid,a.name,b.age FROM logs a JOIN users b ON (a.uid=b.uid);
a   苹果  23
a   橙子  23
b   烧鸡  21

计算过程:
在这里插入图片描述

Map阶段只是拆分key和value。
key这里后面的数字是tag,后面在reduce阶段用来区分来自于那个表的数据。tag是附属在key后面的。那为什么会把a(0)和a(1)汇集在一起了呢,是因为对先对a求了hashcode,设在了HiveKey上,所以同一个key还是在一起的。

reduce阶段主要看它是如何把它合并起来了,从图上可以直观的看到,其实就是把tag=1的内容,都加到tag=0的后面,就是这么简单。
代码实现上,就是先临时用个变量把值存储起来在storage里面, storage(0) = [{a, 苹果}, {a, 橙子}] storage(1) = [{23}],当key变化(如a变为b)或全部结束时,会调用endGroup()方法,把内容合并起来。变成[{a,苹果,23}, {a, 橙子,23}]

通过Explan查看执行过程

hive> explain SELECT a.uid,a.name,b.age FROM logs a JOIN users b ON (a.uid=b.uid);
OK

//语法树
ABSTRACT SYNTAX TREE:
  (TOK_QUERY (TOK_FROM (TOK_JOIN (TOK_TABREF (TOK_TABNAME logs) a) (TOK_TABREF (TOK_TABNAME users) b) (= (. (TOK_TABLE_OR_COL a) uid) (. (TOK_TABLE_OR_COL b) uid)))) (TOK_INSERT (TOK_DESTINATION (TOK_DIR TOK_TMP_FILE)) (TOK_SELECT (TOK_SELEXPR (. (TOK_TABLE_OR_COL a) uid)) (TOK_SELEXPR (. (TOK_TABLE_OR_COL a) name)) (TOK_SELEXPR (. (TOK_TABLE_OR_COL b) age)))))

//阶段
STAGE DEPENDENCIES:
  Stage-1 is a root stage
  Stage-0 is a root stage

STAGE PLANS:
  Stage: Stage-1
    Map Reduce
      Alias -> Map Operator Tree: //mapper阶段
        a 
          TableScan //扫描表, 就只是一行一行的传递下去而已
            alias: a
            Reduce Output Operator //输出给reduce的内容
              key expressions: // key啦,这里的key是uid,就是我们写在ON子句那个,你可以试试加多几个条件
                    expr: uid
                    type: string
              sort order: + //排序
              Map-reduce partition columns://分区字段,貌似是和key一样的
                    expr: uid
                    type: string
              tag: 0 //用来区分这个key是来自哪个表的
              value expressions: //reduce用到的value字段
                    expr: uid
                    type: string
                    expr: name
                    type: string
        b 
          TableScan //扫描表, 就只是一行一行的传递下去而已
            alias: b
            Reduce Output Operator //输出给reduce的内容
              key expressions: //key
                    expr: uid
                    type: string
              sort order: +
              Map-reduce partition columns: //分区字段
                    expr: uid
                    type: string
              tag: 1 //用来区分这个key是来自哪个表的
              value expressions: //值
                    expr: age
                    type: int
      Reduce Operator Tree: // reduce阶段
        Join Operator // JOIN的Operator
          condition map:
               Inner Join 0 to 1 // 内连接0和1表
          condition expressions: // 第0个表有两个字段,分别是uid和name, 第1个表有一个字段age
 {VALUE._col0} {VALUE._col1}
 {VALUE._col1}
          handleSkewJoin: false //是否处理倾斜join,如果是,会分为两个MR任务
          outputColumnNames: _col0, _col1, _col6 //输出字段
          Select Operator //列裁剪(我们sql写的select字段)
            expressions:
                  expr: _col0
                  type: string
                  expr: _col1
                  type: string
                  expr: _col6
                  type: int
            outputColumnNames: _col0, _col1, _col2
            File Output Operator //把结果输出到文件
              compressed: false
              GlobalTableId: 0
              table:
                  input format: org.apache.hadoop.mapred.TextInputFormat
                  output format: org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat

  Stage: Stage-0
    Fetch Operator
      limit: -1

三、谓词下推

虽然hive或spark会为我们优化sql,进行谓词下推,但还是要了解并且养成良好的书写习惯
概括:所谓谓词下推,就是将尽可能多的判断更贴近数据源,以使查询时能跳过无关的数据。用在SQL优化上来说,就是先过滤再做聚合等操作
在这里插入图片描述

看图和文字有些抽象,举例论证:
就是将这个sql

select count(0) 
from A Join B on A.id = B.id 
where A.a > 10 and B.b < 100;

转化为:

select count(0) 
from (
    select id from A  where a>10
) A1 
Join (
    select id from B  where b<100
) B1 on A1.id = B1.id;

通过查看执行计划,可以看到,在处理Join操作之前需要首先对A和B执行TableScan操作,然后再进行Join,再执行过滤,最后计算聚合函数返回,但是如果把过滤条件 A.a > 10 和 B.b < 100 分别移到A表的TableScan和B表的TableScan的时候执行,可以大大降低Join操作的输入数据

四、Hive查询操作优化

1、数据清洗

  1. 读取表时分区过滤,避免全表扫描。
  2. 数据过滤之后再JOIN。
  3. 重复使用数据时,避免重复计算,构建中间表,重复使用中间表。

2、数据倾斜

数据倾斜: shuffle之后Key的分布不均导致分配到 Reduce 端的数据不均匀,出现个别 Reduce 的数据过大,执行时间过长而出现的现象。
数据倾斜的表现: 而当其中每一组的数据量过大时,会出现其他组的计算已经完成而这里还没计算完成,其他节点的一直等待这个节点的任务执行完成,所以会看到一直map 100% reduce 99%的情况,大概率是发生了数据倾斜。
容易造成数据倾斜产生的原因:

  1. 数据业务本身的特性,如某作为key值的字段重复较多
  2. 小表join大表,join时其中一个表较小,但是key集中分发到某一个或几个Reduce上的数据远高于平均值
  3. join时,大表与大表关联,但是很多数据没关联上,导致产生了空值
  4. count(distinct) 时某特殊值过多,导致数据倾斜
  5. group by 时因为分区不合理导致数据倾斜,如group by 的字段某类值过多导致数据倾斜
    总结:让map节点的输出数据更均匀的分布到reduce节点中去,是解决数据倾斜的最终目标。

3、数据倾斜优化

①小表 join 大表解决方案

通过设置

hive.auto.convert.join=true; 
hive.mapjoin.smalltable.filesize=25000000; \\25M

该参数能将小表(小于hive.mapjoin.smalltable.filesize该配置的表)先加载在Map端进行Join操作
在这里插入图片描述

②大表 join 大表解决方案

(1)空Key过滤:有时可能因为key为空的数据量过多,空值都到一个Reduce端,导致出现数据倾斜,此时我们可以在join之前将Key为空的数据过滤掉。
(2)空Key转换:有时可能某些Key为空,但对应的数据并不是异常数据,此时不能简单的进行过滤,我们可以通过将空Key进行转换,例如将Key转换成一个字符串加上一个随机数:concat(‘Null’ + rand()),就能把倾斜的数据分到不同的reduce上

③count(distinct )大量相同特殊值或数据量较大

当数据量毕竟较大时,count操作中只有一个Reduce,那么这个Reduce就会很难完成任务。此时,可以通过Group By + Count的方式替换
如:

-- 优化前
select count(distinct id) from tablename;
-- 优化后
select count(1) from (select distinct id from tablename) tmp;
select count(1) from (select id from tablename group by id) tmp;

4、join过程中出现数据倾斜产生解决方案

对于join过程来说,如果出现较多的key值为空或异常的记录,或key值分布不均匀,就容易出现数据倾斜,可以通过如下配置

-- 如果是join过程中出现倾斜 应该设置为true
set hive.optimize.skewjoin=true;
-- 这个是join的键对应的记录条数,超过这个值则会进行优化
set hive.skewjoin.key=100000;

由于Hive 在join的时候会将相同的key 在最后都汇聚到同一个Reduce 进行处理 , 所以当Join 操作中某个表中的一些Key 数量远远大于其他,则处理该Key的Reduce 将成为瓶颈 .
如 :

select a.* , b.* 
from table_a a 
join table_b b on a.id =b.id;    

如果table_a中的id数量远多于table_a中的其他id ,则会数据倾斜;
该配置适用范围:
在这里插入图片描述
看一下GenMRSkewJoinProcessor.skewJoinEnabled方法的实现:
在这里插入图片描述

从上面的代码中,可以看到要使用skew join优化,必须满足如下的条件:
1、开启优化特性,也就是hive.optimize.skewjoin配置项必须是true,默认是false
2、不能是outer join,这里的outer join包括:UNION JOIN,LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN 这几种join

5、group by产生数据倾斜

对于group by 过程来说,如果某一个key值有特别的多的记录,其它key值的记录比较少,容易出现数据倾斜,可以通过如下配置

-- 开启map端聚合
set hive.map.aggr=true;
-- 用于设定Map端进行聚合操作的条目数
set hive.groupby.mapaggr.checkinterval=100000;

-- 可以对Key随机化打散,多次聚合,当选项设定为true时,生成的查询计划有两个MapReduce任务
set hive.group.skewindata=true;

控制生成两个MR Job,第一个MR Job Map的输出结果随机分配到Reduce中减少某些key值条数过多某些key条数过小造成的数据倾斜问题。
在第一个 MapReduce 中,map 的输出结果集合会随机分布到 reduce 中, 每个reduce 做部分聚合操作,并输出结果。这样处理的结果是,相同的 Group By Key 有可能分发到不同的reduce中,从而达到负载均衡的目的;
第二个 MapReduce 任务再根据预处理的数据结果按照 Group By Key 分布到 reduce 中(这个过程可以保证相同的 Group By Key 分布到同一个 reduce 中),最后完成最终的聚合操作。

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

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

相关文章

五月最近一次面试,被阿里P8测开虐惨了...

都说金三银四涨薪季&#xff0c;我是着急忙慌的准备简历——5年软件测试经验&#xff0c;可独立测试大型产品项目&#xff0c;熟悉项目测试流程...薪资要求&#xff1f;5年测试经验起码能要个20K吧 我加班肝了一页半简历&#xff0c;投出去一周&#xff0c;面试电话倒是不少&a…

自动化测试框架类型,你知道几种?此处介绍5种比较常见的

每一个测试人员都应该了解每种框架的优缺点&#xff0c;以帮助你的团队更好地确定最适合的测试的框架&#xff0c;以达到事半功倍。 什么是测试自动化框架? 自动化测试框架就是用于测试自动化的框架。具体来说&#xff0c;它提供了自动化测试用例编写、自动化测试用例执行、自…

分布式ID的选择

一、分布式ID策略 1.目前数据库主键ID生成的策略整理了这么几个&#xff0c;我们分析下每个的问题 1.1 数据库自增ID分析 我们创建数据库的时候&#xff0c;指定我们的id字段是主键&#xff0c;并且是自增的 create table demo_table ( id int(10) primary key auto_increm…

【个人笔记】真寻bot部署记录+源码食用记录

安装 0. 系统配置 Centos v8.2 1. 安装 使用真寻bot https://github.com/zhenxun-org/zhenxun_bot-deploy bash <(curl -s -L https://raw.githubusercontent.com/zhenxun-org/zhenxun_bot-deploy/master/install.sh)选择1&#xff0c;安装go-cqhttp和zhenxun_bot&…

SQL Developer如何导入时间格式的字段?

SQL developer有一个非常好用的功能&#xff0c;就是导入本地的数据文件。但是导入文件时&#xff0c;如果含时间字段&#xff0c;常常无法导入成功&#xff0c;如何解决&#xff1f; 第一步&#xff1a;处理表格时间格式 选中时间列&#xff0c;右击弹出【设置单元格格式】—…

指令微调数据集整理

文章目录 开源指令数据集斯坦福数据链家数据 垂直领域数据集医疗领域的英文数据医疗领域的中文数据 COIG数据集&#xff08;可商用的中文数据集&#xff09; 开源指令数据集 斯坦福数据 斯坦福52K英文指令数据&#xff1a;https://github.com/tatsu-lab/stanford_alpaca 52K …

硬件工程师-电路设计2-RC电路

RC滤波 滤波 把干扰的杂波滤除掉。 问题&#xff1a;为什么R和C可以实现滤波&#xff1f; 源 回路 阻抗 理想中的信号源是没有干扰的 实际中是有干扰的 受磁场 电场 地的影响&#xff0c;信号源会耦合一些高频干扰波进来&#xff0c;驼在信号源上。 ---…

链接思想的力量:如何将你的思维联系起来以提高你的学习和记忆能力

是否发现自己收藏的笔记很少做回顾和复盘&#xff1f; 链接你的思维&#xff08;LYT&#xff09;是另一个笔记系统&#xff0c;LYT笔记系统理念进入个人知识管理&#xff08;PKM&#xff09;会提供更有效和令人满意的笔记体验。 在今天的文章中&#xff0c;您将了解什么是链接…

踩坑记录:python + appium +adb 运行出现问题

搭建使用appium运行的环境&#xff0c;准备做个自己的app自动化&#xff0c;环境均已搭建好&#xff0c; appium-doctor 均正常使用 使用python下载Appium-Python-Client &#xff0c;pip 默认安装是最新版本&#xff0c;然后编写demo测试 from appium import webdriver i…

赛灵思-Zynq UltraScale+ MPSoC:QT与OPENCV交叉编译环境搭建

赛灵思-Zynq UltraScale MPSoC&#xff1a;QT与OPENCV交叉编译环境搭建 1、MPSOC 交叉编译环境简介 使用Linux交叉编译工具在开发中可以摆脱对petalinux的依赖&#xff0c;直接使用Linux交叉编译工具进行编译&#xff0c;可以使开发更加便捷。 由于获取Linux编译工具链需要用…

如何在华为OD机试中获得满分?Java实现【跳跃游戏 II】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

MyBatis中discriminator鉴别器如何使用?你若不会,我手把手教你 | 超级详细,建议收藏

1. 前言 不知道大家在平时有没有手写sql的习惯&#xff0c;当还没有开源mybatis-plus时&#xff0c;手写sql那是非常的常见&#xff0c;但是在维护一个老项目的时候&#xff0c;竟然勾起了我的一丝回忆。涉及到一个需求&#xff0c;我要追溯到它sql语句上&#xff0c;发现了一个…

【PC迁移与管理】上海道宁为每个用户和每个 PC 传输和迁移场景提供解决方案——PCmover

PCmover 是一款 可以自动将所有选定文件、 文件夹、设置、用户配置文件 甚至应用程序 从旧PC传输、恢复和升级到 新PC或操作系统的软件 而且由于 大多数迁移的应用程序 都已安装在新PC上即可使用 通常无需查找旧CD 以前下载的程序 序列号或许可证代码 开发商介绍 La…

mongodb-分片集群-搭建

分片集群 高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。 为了解决这些问题,有两个基本的方法: 垂直扩展和水平扩展。 垂直扩展&#xff1a;增加更多的…

嵌入式 QT 基于mplayer的音乐播放器

1、实现功能 2、音乐播放界面 2.1 界面程序 2.1.1 界面控制初始化 2.1.2 控件风格程序 3、 歌曲列表界面 3.1.1 在 widget.h 定义 QListWidge 对象指针 3.1.2 在 memberInit 函数中添加 QlistWidge 初始化 3.1.3 在 setMusicPlayStyle 函数中设置其风格 4、音乐播放功…

第四章 程序的控制结构

文章目录 第四章 程序的控制结构4.1 程序的三种控制结构4.1.1 程序流程图4.1.2 程序控制结构基础4.1.3 程序控制结构扩展 4.2 程序的多分支结构4.2.1 单分支结构&#xff1a;if4.2.2 二分支结构&#xff1a;if-else4.2.3 多分支结构&#xff1a;if-elif-else4.2.4 判断条件及组…

Github Copilot AI配对开发者编程,提升项目建设进度

Github Copilot是什么&#xff1f; GitHub Copilot 是结对编程的虚拟版本。结对编程是一种常见的敏捷软件开发技术 —— 即两个开发人员在同一个项目上并肩协作&#xff0c;轮流编写代码并检查合作伙伴的输出。 Copilot 可以支持十几种语言&#xff0c;与 Python、JavaScript、…

一文揭秘高效稳定的 Apache Doris 内存管理机制

作者&#xff1a;SelectDB 高级研发工程师、Apache Doris Committer 邹新一 背景 Apache Doris 作为基于 MPP 架构的 OLAP 数据库&#xff0c;数据从磁盘加载到内存后&#xff0c;会在算子间流式传递并计算&#xff0c;在内存中存储计算的中间结果&#xff0c;这种方式减少了频…

Vue2创建脚手架小案例

Vue CLI是一个官方提供的命令行工具&#xff0c;用于快速创建Vue.js项目和管理项目依赖项。下面是使用Vue CLI创建Vue.js项目的基本步骤&#xff1a; 首先&#xff0c;确保已安装Node.js和npm包管理器。可以在终端输入以下命令来检查它们的版本&#xff1a; node -v npm -v如…

MySQL备份

MySQL的备份方式有哪几种&#xff1f;分别如何实现&#xff1f; 目录 一、数据的备份类型 1、数据的备份类型根据其自身的特性主要分为以下几组&#xff1a; 二、MySQL备份数据的方式 三、常见的备份工具 1、一般情况下, 我们需要备份的数据分为以下几种 2、备份工具 3…