调优--学习笔记

1,Presto调优

数据存储格式

1)合理设置分区
与Hive类似,Presto会根据元信息读取分区数据,合理的分区能减少Presto数据读取量,提升查询性能。
2)使用列式存储
Presto对ORC文件读取做了特定优化,因此在Hive中创建Presto使用的表时,建议采用ORC格式存储。相对于Parquet,Presto对ORC支持更好。
Parquet和ORC一样都支持列式存储,但是Presto对ORC支持更好,而Impala对Parquet支持更好。在数仓设计时,要根据后续可能的查询引擎合理设置数据存储格式。
3)使用压缩
数据压缩可以减少节点间数据传输对IO带宽压力,对于即席查询需要快速解压,建议采用Snappy压缩。
4)预先排序
对于已经排序的数据,在查询的数据过滤阶段,ORC格式支持跳过读取不必要的数据。比如对于经常需要过滤的字段可以预先排序。

INSERT INTO table nation_orc partition(p) SELECT * FROM nation SORT BY n_name;

如果需要过滤n_name字段,则性能将提升。

SELECT count(*) FROM nation_orc WHERE n_name=’AUSTRALIA’; 

SQL优化

1)只选择使用必要的字段
由于采用列式存储,选择需要的字段可加快字段的读取、减少数据量。避免采用*读取所有字段。
[✔]: SELECT time,user,host FROM tbl
[✘]: SELECT * FROM tbl

2)过滤条件必须加上分区字段
对于有分区的表,where语句中优先使用分区字段进行过滤。acct_day是分区字段,visit_time是具体访问时间。
[✔]: SELECT time, user, host FROM tbl where acct_day=20171101
[✘]: SELECT * FROM tbl where visit_time=20171101

3)Group By语句优化 (presto)
合理安排Group by语句中字段顺序对性能有一定提升。将Group By语句中字段按照每个字段distinct数据多少进行降序排列。
[✔]: SELECT GROUP BY uid, gender
[✘]: SELECT GROUP BY gender, uid

4)Order by时使用Limit
Order by需要扫描数据到单个worker节点进行排序,导致单个worker需要大量内存。如果是查询Top N或者Bottom N,使用limit可减少排序计算和内存压力。
[✔]: SELECT * FROM tbl ORDER BY time LIMIT 100
[✘]: SELECT * FROM tbl ORDER BY time

5)用regexp_like代替多个like语句
Presto查询优化器没有对多个like语句进行优化,使用regexp_like对性能有较大提升

[]
SELECT
  ...
FROM
  access
WHERE
  regexp_like(method, 'GET|POST|PUT|DELETE')

[]
SELECT
  ...
FROM
  access
WHERE
  method LIKE '%GET%' OR
  method LIKE '%POST%' OR
  method LIKE '%PUT%' OR
  method LIKE '%DELETE%'

6)使用Join语句时将大表放在左边(presto)
Presto中join的默认算法是broadcast join,即将join左边的表分割到多个worker,然后将join
右边的表数据整个复制一份发送到每个worker进行计算。如果右边的表数据量太大,则可能会报内存溢出错误。

[] SELECT ... FROM large_table l join small_table s on l.id = s.id
[] SELECT ... FROM small_table s join large_table l on l.id = s.id

7)使用Rank函数代替row_number函数来获取TopN
在进行一些分组排序场景时,使用rank函数性能更好。

[]
SELECT checksum(rnk)
FROM (
  SELECT rank() OVER (PARTITION BY l_orderkey, l_partkey ORDER BY l_shipdate DESC) AS rnk
  FROM lineitem
) t
WHERE rnk = 1

[]
SELECT checksum(rnk)
FROM (
  SELECT row_number() OVER (PARTITION BY l_orderkey, l_partkey ORDER BY l_shipdate DESC) AS rnk
  FROM lineitem
) t
WHERE rnk = 1

内存调优

1 User & System memory
Presto把自己管理的内存分为两大类:user memory和system memory,所谓的user memory是跟用户数据相关的,比如读取用户输入数据会占据相应的内存,这种内存的占用量跟用户底层数据量大小是强相关的;system memory则是执行过程中衍生出的副产品,比如tablescan表扫描,write buffers写入缓冲区,跟查询输入的数据本身不强相关的内存。
执行过程中,presto是从具体的内存池中来实现分配user memory和system memory的。Presto有两种内存池,分别为常规内存池GENERAL_POOL、预留内存池RESERVED_POOL。
注:0.201之后SYSTEM_POOL已经被废弃,GENERAL_POOL扮演了之前GENERAL_POOL及SYSTEM_POOL的作用,提供user memory和system memory。
1.GENERAL_POOL:在一般情况下,一个查询执行所需要的user/system内存都是从general pool中分配的,reserved pool在一般情况下是空闲不用的。
2.RESERVED_POOL:大部分时间里是不参与计算的,但是当集群中某个Worker节点的general pool消耗殆尽之后,coordinator会选择集群中内存占用最多的查询,把这个查询分配到reserved pool,这样这个大查询自己可以继续执行,而腾出来的内存也使得其它的查询可以继续执行,从而避免整个系统阻塞。
reserved pool到底多大呢?这个是没有直接的配置可以设置的,他的大小上限就是集群允许的最大的查询的大小(query.total-max-memory-per-node)。
reserved pool也有缺点,一个是在普通模式下这块内存会被浪费掉了,二是大查询可以用Hive来替代。因此也可以禁用掉reserved pool(experimental.reserved-pool-enabled=false),那系统内存耗尽的时候没有reserved pool怎么办呢?它有一个OOM Killer的机制,对于超出内存限制的大查询SQL将会被系统Kill掉,从而避免影响整个presto。
三,Presto由于是完全基于内存的计算,经常出现OOM,需要调整内存。
1、Query exceeded per-node total memory limit of xx
适当增加query.max-total-memory-per-node。
2、Query exceeded distributed user memory limit of xx
适当增加query.max-memory。
3、Could not communicate with the remote task. The node may have crashed or be under too much load
内存不够,导致节点crash,可以查看/var/log/message。

注意:
1、query.max-memory-per-node小于query.max-total-memory-per-node。
2、query.max-memory小于query.max-total-memory。
3、query.max-total-memory-per-node 与memory.heap-headroom-per-node 之和必须小于 jvm max memory,也就是jvm.config 中配置的-Xmx。

2,DWS层实现

Ntille

NTILE()函数它把有序的数据集合 平均分配 到 指定的数量(num)个组中, 如果不能平均分配,则优先分配较小编号的组,并且各个组中能放的行数最多相差1。各个组有编号,编号从1开始,就像我们说的’分区’一样 ,分为几个区,一个区会有多少个。
每个组行数最多相差1的含义:
1、每组的记录数不能大于它上一组的记录数,即编号小的桶放的记录数不能小于编号大的桶。也就是说,第1组中的记录数只能大于等于第2组及以后各组中的记录数。
2、所有组中的记录数要么都相同,要么从某一个记录较少的组(命名为X)开始后面所有组的记录数都与该组(X组)的记录数相同。也就是说,如果有个组,前三组的记录数都是9,而第四组的记录数是8,那么第五组和第六组的记录数也必须是8。

GROUPING SETS、CUBE和ROLLUP

Grouping sets允许用户指定要分组的多个列列表。将不属于分组列的给定子列表的列设置为NULL。
比如,需求分别按照店铺分组、订单组分组、店铺和订单组分组统计订单销售额,并获取三者的结果集(插入到宽表)。可以通过union all多个group by来实现:

select store_id,
       group_id,
       sum(order_amount)
from yp_dwb.dwb_order_detail
group by
    grouping sets (store_id, group_id, (store_id, group_id));

同时,使用grouping sets、cube、rollup这些复杂group语法的SQL只会读取基础数据源一次,而使用union all拼接的SQL会读取基础数据源三次(或更多)。因此当数据源正在频繁变化时,使用union all拼接的方式可能会产生一些奇怪的结果。

CUBE

CUBE操作会生成所提供column所有可能的grouping sets结果。

select store_id,
       group_id,
       sum(order_amount)
from yp_dwb.dwb_order_detail
group by
    cube (store_id, group_id);

ROLLUP

rollup((a),(b),©)等价于grouping sets((a,b,c),(a,b),(a),())。

select store_id,
       group_id,
       sum(order_amount)
from yp_dwb.dwb_order_detail
group by
rollup (store_id,group_id);

GROUPING操作

grouping 返回一个转换为十进制数字的二进制数值集合,指示分组中存在哪些列。 它必须与GROUPING SETS,ROLLUP,CUBE或GROUP BY结合使用,并且其参数必须与相应的GROUPING SETS,ROLLUP,CUBE或GROUP BY子句中引用的列完全匹配。
对于给定的分组,如果分组中包含相应的列,则将位设置为0,否则将其设置为1。
Demo:

select group_id,
       store_id,
       sum(goods_amount),
       grouping(group_id)           as ging,
       grouping(store_id)           as sing,
       grouping(group_id, store_id) as g_s_ing
from yp_dwb.dwb_order_detail
group by
    grouping sets (group_id, store_id, (group_id, store_id));

grouping(group_id)列为0时,可以看到group_id列都是有值的,为1时则相反,证明当前行是按照group_id来进行分组统计的;
grouping(store_id)同理,为0时store_id列有值,为1时store_id为空,证明当前行时按照store_id来进行分组统计的;
grouping(group_id, store_id)是grouping(group_id)、grouping(store_id)二进制数值组合后转换得到的数字:
a.按照group_id分组,则group_id=0,store_id=1,组合后为01,二进制转换为十进制得到数字1;
b.按照store_id分组,则group_id=1,store_id=0,组合后为10,二进制转换为十进制得到数字2;
c.同时按照group_id和store_id分组,则group_id=0,store_id=0,组合后为00,二进制转换为十进制得到数字0。
因此可以使用grouping操作来判断当前数据是按照哪个字段来分组的。

运行时优化

set hive.optimize.skewjoin=true;
默认关闭。
如果大表和大表进行join操作,则可采用skewjoin(倾斜关联)来开启对倾斜数据的优化。
skewjoin原理:
1.对于skewjoin.key,在执行job时,将它们存入临时的HDFS目录,其它数据正常执行
2.对倾斜数据开启map join操作(多个map并行处理),对非倾斜值采取普通join操作
3.将倾斜数据集和非倾斜数据集进行合并Union操作。

开启skewin以后,究竟多大的数据才会被认为是倾斜了的数据呢?
set hive.skewjoin.key=100000;
默认值100000。
如果join的key对应的记录条数超过这个值,就认为这个key产生了数据倾斜,则会对其进行分拆优化。

编译时优化

上面的配置项其实应该理解为hive.optimize.skewjoin.runtime,也就是sql运行时来对偏斜信息进行优化;除此之外还有另外一个配置:
set hive.optimize.skewjoin.compiletime=true;
默认关闭。
此参数的用处和上面的hive.optimize.skewjoin一致,但在编译sql时就已经将执行计划优化完毕。但要注意的是,只有在表的元数据中存储的有数据倾斜信息时,才能生效。因此建议runtime和compiletime都设置为true。
可以通过建表语句来指定数据倾斜元数据:

Union优化

应用了表连接倾斜优化以后,会在执行计划中插入一个新的union操作,此时建议开启对union的优化配置:
set hive.optimize.union.remove=true;
默认关闭。
此项配置减少对Union all子查询中间结果的二次读写,可以避免union输出的额外扫描过程,当我们开启了skewjoin时尤其有用,建议同时开启。

set hive.optimize.skewjoin=true;
set hive.optimize.skewjoin.compiletime=true;
set hive.optimize.union.remove=true;

Map阶段聚合

hive.map.aggr=true;
开启map端combiner。此配置可以在group by语句中提高HiveQL聚合的执行性能。这个设置可以将顶层的聚合操作放在Map阶段执行,从而减轻数据传输和Reduce阶段的执行时间,提升总体性能。默认开启,无需显示声明。

两次MR

开启参数

set hive.groupby.skewindata=true;

思想

第一次MR
reduce拉取的数据是随机拉取,数据就均衡分布了,不会产生数据倾斜
第二次MR
reduce拉取的数据按照相同key的值发送到同一个reduce这种操作。因为上一次的数据量减少了,就不会产生数据倾斜

空key处理

空key的过滤

---2表连接
select  * from  A left join  B  on A.id = B.id
---
select * from (select  * from  A where id is not null )A  left join  (select * from B where id is not null ) B  on A.id = B.id

空key的转换

 select * from a LEFT JOIN  b ON CASE WHEN a.id IS NULL THEN round(rand(),2)*100 ELSE a.id END = CASE WHEN b.id IS NULL THEN round(rand(),2)*100 ELSE a.id END;

相当于将很多的空值转换成100份数据,就打散了

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python】tensorflow学习的个人纪录(2)

actor.learn(s, a, td_error)def learn(self, s, a, td):s s[np.newaxis, :]feed_dict {self.s: s, self.a: a, self.td_error: td}_, exp_v self.sess.run([self.train_op, self.exp_v], feed_dict)return exp_v输入变量的数值: 步进: []---->[…

ER图是什么,怎么画?

ER图(Entity-Relationship Diagram)是一种用于描述实体间关系的图形化表示方法。它主要用于数据库设计,可以清晰地展示实体、属性和实体间的联系。常用的ER图类型包括: 实体-关系模型(Entity-Relationship Model&…

最新最全的Postman接口测试: postman实现参数化

什么时候会用到参数化 比如:一个模块要用多组不同数据进行测试 验证业务的正确性 Login模块:正确的用户名,密码 成功;错误的用户名,正确的密码 失败 postman实现参数化 在实际的接口测试中,部分参数…

WordPress定时文章自动发布技巧

对于许多WordPress站长来说,文章的管理和发布计划往往是一个头疼的问题。随着内容的不断增加,时间表的调整以及发布频率的把握成为了让人焦头烂额的挑战。 一、时间管理难题 对于博客管理员来说,时间管理一直是个令人困扰的问题。在忙碌的生…

Vue3实现滚动到容器底部时发送请求,加载新数据

问题来源 在项目中出现了需要在容器滚动到底部时,加载新的数据的需求,以下是解决的方案笔记 解决 画了个流程图: 如图,先添加一个动态加载的图标,还有全部数据载完的《到底啦...》 大概这么个样子,之后呢…

苍穹外卖——地址簿功能

地址簿功能代码 1. 地址簿功能 1.1 需求分析和设计 查询地址列表新增地址修改地址删除地址设置默认地址查询默认地址 1.1.1 接口设计 根据上述原型图先粗粒度设计接口,共包含7个接口。 接口设计: 新增地址查询登录用户所有地址查询默认地址根据id…

C++基础 -35- string类

string类的格式 string a;如下图,使用string类比常规的字符串处理方便很多 而且需要进行的字符串处理,在类中都能完成 #include "iostream"using namespace std;extern "C" {#include "string.h" }int main() {//c的写…

SpringBoot框架结合Redis实现分布式锁

一、SpringBoot结合 Redis实现分布式锁 1.1、什么是分布式锁 分布式锁,是在分布式的环境下,才会使用到的一种同步访问机制,在传统的单体环境里面,不存在分布式锁的概念,只有在分布式环境里面,才有分布式锁…

【Python】tensorflow学习的个人纪录(3)

sess tf.Session()actor Actor(sess, n_featuresN_S, lrLR_A, action_bound[-A_BOUND, A_BOUND])步进:

工具网站:随机生成图片的网站

一个随机生成图片的网站:Lorem Picsum。 有时候,我们做静态页面需要大量图片去填充内容,以使用该网站去生成指定尺寸的图片。每次打开页面都会获取不同的图片,就不用我们做静态页面开发的时候,绞尽脑汁去找图片了。 …

【滑动窗口】水果成篮

水果成篮 904. 水果成篮 - 力扣(LeetCode) 文章目录 水果成篮题目描述问题转化 算法原理解法一解法二 代码编写C代码:使用容器数组模拟哈希表 Java代码使用容器数组模拟哈希表 题目描述 你正在探访一家农场,农场从左到右种植了一…

【hacker送书活动第7期】Python网络爬虫入门到实战

第7期图书推荐 内容简介作者简介大咖推荐图书目录概述参与方式 内容简介 本书介绍了Python3网络爬虫的常见技术。首先介绍了网页的基础知识,然后介绍了urllib、Requests请求库以及XPath、Beautiful Soup等解析库,接着介绍了selenium对动态网站的爬取和S…

红队攻防实战之Access注入

若盛世将倾,深渊在侧,我辈当万死以赴 访问漏洞url: 1.Access联合查询 判断是否有注入 and 11正常,and 12出错 判断字段数 order by 7正常 order by 8出错 爆破出表名并判断回显点为2,5 查看字段内容,将字段名填入回…

37. 解数独

题目描述 编写一个程序,通过填充空格来解决数独问题。 数独的解法需 遵循如下规则: 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图) …

思维模型 反馈效应

本系列文章 主要是 分享 思维模型,涉及各个领域,重在提升认知。反馈促进改进。 1 反馈效应的应用 1.1 反馈效应在营销中的应用 1 “可口可乐与百事可乐之战” 在 20 世纪 80 年代,可口可乐公司是全球最大的饮料公司之一,其市场…

常见的线程安全问题及解决

1. 什么是线程安全 线程安全指的是当多个线程同时访问一个共享的资源时,不会出现不确定的结果。这意味着无论并发线程的调度顺序如何,程序都能够按照设计的预期来运行,而不会产生竞态条件(race condition)或其他并发问…

算法设计与实现--贪心篇

贪心算法 贪心算法是一种在每一步选择中都采取当前状态下最优决策的算法,以期望能够通过一系列局部最优的选择达到全局最优。贪心算法的关键是定义好局部最优的选择,并且不回退,即一旦做出了选择,就不能撤销。 一般来说&#xf…

洛谷 P5711 闰年判断 C++代码

目录 前言 思路点拨 AC代码 结尾 前言 今天我们来做洛谷上的一道题目。 网址:【深基3.例3】闰年判断 - 洛谷 题目: 思路点拨 首先题目让我们输入一个年份,因此我们需要定义一个变量year,来存储输入的年份: in…

Bean的加载控制

Bean的加载控制 文章目录 Bean的加载控制编程式注解式ConditionalOn*** 编程式 public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {try {Class<?> clazz Class.forName("…

Nginx 具体应用

1 Nginx 1.1 介绍 一款轻量级的 Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器。它占有的内存少&#xff0c;并发能力强&#xff0c;中国大陆使用 nginx 的网站有&#xff1a;百度、京东、新浪、网易、腾讯、淘宝等。第一个公开版本发布于…