Uploaded by a1045743117

GaussDB(DWS)数据库性能调优

advertisement
数据库性能调优
版权所有© 2019 华为技术有限公司
前言
⚫
性能是连接数据库的应用中不可或缺的关键因素,一个APP项目的代码质量优劣可以通过其性能来衡
量。性能调优是通过采用各种技术手段,使得SQL语句能够以高效的方式运行,以较小的消费数据库
资源达到预期的性能目标。
⚫
大部分场景连接数据库的应用出现性能问题,70%以上是由不合格的sql引起,因此后端开发工程师
应对上线生产环境的sql有足够的质量意识,懂算法和sql运行原理,而掌握数据库SQL性能调优的基
本方法是每个开发人员都应该具备的基本技能。
⚫
本章将重点介绍GaussDB(DWS)数据库调优的基本思路、常见的SQL性能问题的定位方法以及解决方
案。通过优化和改写SQL语句,可以显著提升数据库的性能。在性能调优过程中,我们需要深入理解
数据库的SQL运行原理和调优思路,并结合具体场景分析和优化sql语句,通过sql改写、索引调整、
执行计划等方面的调测,以达到最佳的性能表现。
第1页
版权所有© 2019 华为技术有限公司
DWS逻辑架构
业务应用
OM
CM
GTM
WLM
CN
业务应用
..
CN
网络通道(10GE)
DN
DN
Storage
Storage
OM
运维管理模块,提供日常运维、配置管理的管
CM
集群管理模块,管理和监控分布式系统中各个
…
GTM
理接口、工具。
WLM
功能单元和物理资源的运行情况,确保整个系
协调节点,负责接收来自应用的访问请求,
DN
Data Node上并行执行。
第2页
版权所有© 2019 华为技术有限公司
Storage
Storage
全局事务控制器,负责生成和维护全局事务ID、
事务快照、时间戳等需要全局唯一的信息。
工作负载管理器,控制系统资源的分配,防止
过量业务负载对系统的冲击而导致业务拥塞和
数据节点,负责存储业务数据(支持行存、列
存、混合存储)、执行数据查询任务以及向CN
并向客户端返回执行结果。
CN负责分解任务,并调度任务分片在各
DN
系统崩溃。
统的稳定运行。
CN
DN
返回执行结果。
Storage
服务器的本地存储资源,持久化存储数据。
第3页
版权所有© 2019 华为技术有限公司
第4页
版权所有© 2019 华为技术有限公司
专利技术:一种聚簇存储方法及装置
第5页
版权所有© 2019 华为技术有限公司
第6页
版权所有© 2019 华为技术有限公司
框架介绍—数据分布和分区
第7页
版权所有© 2019 华为技术有限公司
Stream算子—举例1
第8页
版权所有© 2019 华为技术有限公司
Stream算子—举例2
第9页
版权所有© 2019 华为技术有限公司
Stream算子—举例3
第10页
版权所有© 2019 华为技术有限公司
Stream算子—举例4
第11页
版权所有© 2019 华为技术有限公司
目标
⚫
第12页
学完本课程后,您将能够:

掌握使用Explain命令查看语句的执行计划,并学会收集跟性能有关的执行信息;

理解调优的基本原则和流程;

学会静态调优、动态调优的常用方法;

掌握SQL语句性能问题的分析思路,学会正确的选择优化策略进行SQL性能调优。
版权所有© 2019 华为技术有限公司
目录
1. Explain 执行计划
2. 调优原则
3. 调优流程
4. 静态调优
5. 动态调优
第13页
版权所有© 2019 华为技术有限公司
Explain
⚫
执 行 EXPLAIN VERBOSE 命 令 , 收 集 DML 语 句 ( SELECT/UPDATE/INSERT/DELETE/MERGE
INTO/CREATE TABLE AS)详细的计划信息
EXPLAIN VERBOSE
SELECT
sum(l_extendedprice * (1 - l_discount)) AS revenue
FROM orders
INNER JOIN lineitem ON l_orderkey = o_orderkey
WHERE o_orderdate >= '1994-01-01'::date AND o_orderdate < '1994-01-01'::date + interval '1 year';
⚫
执行EXPLAIN PERFORMANCE命令,收集DML语句(SELECT/UPDATE/INSERT/DELETE/MERGE
INTO/CREATE TABLE AS)详细的执行信息
EXPLAIN PERFORMANCE
SELECT
sum(l_extendedprice * (1 - l_discount)) AS revenue
FROM orders
INNER JOIN lineitem ON l_orderkey = o_orderkey
WHERE o_orderdate >= '1994-01-01'::date AND o_orderdate < '1994-01-01'::date + interval '1 year';
第14页
版权所有© 2019 华为技术有限公司
Explain - perf 信息 (1)
⚫
⚫
PERFORMANCE选项可以打印执行中的所有相关信息

Plan Information:以表格形式显示整个执行过程中每个算子的执行概要信息

SQL Diagnostic Information:SQL自诊断信息

Predicate Information:算子计算信息,如scan的filter条件,join的 join 条件

Memory Information:算子计算过程中内存消耗信息

Targetlist Information:算子输出列信息

Datanode Information:算子在每个DN上执行的详细信息

User Define Profiling:性能Profile信息

Query Summary :Query执行的概要信息
性能分析主要关注Plan Information/SQL Diagnostic Information/Datanode Information
/Predicate Information 这四部分信息
⚫
第15页
大集群下,对于复杂SQL,建议使用Explain analyze打印概要的实际执行信息。
版权所有© 2019 华为技术有限公司
Explain - perf 信息 (2)
⚫
Plan Information 相比verbose选项生成的执行计划,新增实际执行的相关信息。

A-time
算子的实际执行时间,在DN上的输出由[]括起来由逗号分割的两个值,分别表示此算子在不同DN上执行的最短时间和最长时间。

A-row
算子的实际输出的元组数,为各个DN上算子输出的元组数的总和。

PeakMemory
算子运行过程中消耗的内存峰值,在DN上的输出由[]括起来由逗号分割的两个值,分别表示此算子在不同DN上执行的最小内存
消耗和最大内存消耗。

A-width
算子每行元组的实际宽度,仅涉及重内存使用算子。
第16页
版权所有© 2019 华为技术有限公司
Explain - perf 信息 (3)
⚫
SQL Diagnostic Information部分是SQL自诊断信息,
诊断信息类型
verbose可诊断
•
统计信息未收集
•
大表等值连接使用Nestloop
•
分区不剪枝
•
大表Broadcast
•
SQL不下推
•
数据倾斜
•
HashJoin中大表做内表
•
索引不合理
性能问题对应的算子,对照Plan
Information 中的id列
第17页
版权所有© 2019 华为技术有限公司
具体诊断信息描述
performance可诊断
Explain 执行计划 - perf 信息 (4)
⚫
DataNode Information 描述算子在各DN的执行时间、CPU、Buffer的使用情况

执行时间 (actual time)
如果这个值在各个DN上存在较大差异,可初步判断存在
计算倾斜(各个DN上承担的计算量差异过大)。

输出元组数 (rows)
结合执行时间进一步佐证是否存在计算倾斜。

Plan Information
Buffer命中率 (hit)
主要针对Scan算子作数据扫描时。从性能角度来说,buffer
命中率越高越好,需要增大集群的shared_buffers (行存) 、
cstore_buffers(列存)配置参数的取值。

CPU的执行cycle
在算子执行期间,执行所消耗的CPU cycle。
第18页
版权所有© 2019 华为技术有限公司
Explain 执行计划 - perf 信息 (5)
⚫
User Define Information 描述算子执行
中,关键动作的性能打桩信息
第19页

CN 和 DN 建立连接

数据加载

数据解压

列存的min/max check

列存场景的Batch加载

算子上的投影和过滤计算
➢
低效自定义函数会导致这一步耗时过长
版权所有© 2019 华为技术有限公司
本节小结
⚫
本节主要介绍通过Explain命令查看语句的执行计划的两种常用方法,并以示例的
查询语句为例,详细介绍Explain Performance 命令收集到的各部分执行信息及
SQL性能调优过程需要重点关注的信息。
⚫
更多执行计划解读信息请参考
https://bbs.huaweicloud.com/blogs/200449
https://bbs.huaweicloud.com/blogs/197945
第20页
版权所有© 2019 华为技术有限公司
目录
1. Explain 执行计划
2. 调优原则
3. 调优流程
4. 静态调优
5. 动态调优
第21页
版权所有© 2019 华为技术有限公司
调优原则
⚫
基本原则(唯一原则):资源利用最大化原则

资源:CPU、内存、磁盘IO、网络IO

SQL语句应当尽量高效,节省资源开销
◼
以最优的执行方式实现功能
◼
举例:典型点查询
1). seqscan+filter (读取每一条元组和点查询条件进行匹配)
2). indexscan (基于表建立索引表)
indexscan 可以以更小的代价实现相同的查询效果。

SQL语句应当充分利用资源
◼
应当尽量充分利用资源,实现性能的极致
◼
举例:sort 排序
在内存可控的范围内尽量保证数据不下盘,让数据在内存中排序,从而提升排序效率,保证性能的最大收益。
第22页
版权所有© 2019 华为技术有限公司
目录
1. Explain执行计划
2. 调优原则
3. 调优流程
4. 静态调优
5. 动态调优
第23页
版权所有© 2019 华为技术有限公司
调优流程
⚫
静态调优
静态调优
根据硬件资源和客户的业务特征确定集群部署方案、表定义。

表定义:行列存、复制/哈希分布等

集群部署方案和表定义一旦确定,后续改动的代价会比较大。
开始
集群部署方案
表定义&加载数据
⚫
执行态调优 (动态调优)
SQL试跑
根据SQL语句执行的实际情况采取针对性干预SQL执行计划的方式来提升性能。

SQL改写

GUC参数干预

Plan Hint
结束
Y
性能OK?
N
性能调优
执行态调优
第24页
版权所有© 2019 华为技术有限公司
目录
1. Explain执行计划
2. 调优原则
3. 调优流程
4. 静态调优
5. 动态调优
第25页
版权所有© 2019 华为技术有限公司
静态调优 - 表定义
⚫
数据分布在DN上,好的表定义要求:

表数据均匀分布在各个DN
表定义流程
业务特征
Start
数据特征
防止单个DN数据过多导致集群有效容量下降。
选择合适分布列避免数据分布倾斜!
存储模型
PCK列分区
键
行/列存
表Scan压力均匀分散在各个DN
更多
点这里!
避免单DN的Scan压力过大,形成Scan的单节点瓶颈。

避免把基表上的等值filter中的列作为分布列!

减少扫描数据量:通过分区机制实现

尽量减少随机IO:通过聚簇/局部聚簇可以实现这点

尽量避免数据shuffle

减小网络压力。
建议选择join-condition或者group by列为分布列!
小表?
版权所有© 2019 华为技术有限公司
Hash表
分布列优
先级排序
Y
选取高优先级
分布列建表
复制表
N
Y
表定义
End
第26页
N
分布列选取
分布
均匀?
导入样本数据
静态调优 - 选择存储类型
⚫
⚫
存储类型的重要性

存储类型决定存储格式,进而影响I/O操作行为

客户业务属性决定表的存储类型。
行列存选择依据
存储
类型
行存
列存
第27页
适用场景
点查询(返回记录少,基于索引的简单查询)
增删改比较多的场景
统计分析类查询 (group , join 多的场景)
即席查询 (查询条件列不确定,行存无法确定索引)
版权所有© 2019 华为技术有限公司
静态调优 - 分布列 – 简述
⚫
复制 (Replication)

⚫
⚫
第28页
DN1
T1
集群中每个DN实例上都有一份全量表数据

Join操作可减小重分布造成的网络开销

存在数据冗余

适用于小表、维表
哈希 (Hash) -- 8.1.3之前默认分布方式
T2.p1
T3
复制
T1
hash
col1 col2
data0
data1 T2
data2
……
data n
T1
数据通过Hash方式散列到集群的所有DN实例
T2.p2

读写数据可充分利用各个节点IO资源,提升读写速度
T3

适用于数据量大的表
(初始DN+1)%DN数
data0
data1
data2 T3
data3
data4
DN3

数据通过轮询方式发放到集群内所有DN实例
T1

读写数据可充分利用各个节点IO资源,提升读写速度
T2.p3

适用于数据量大的表,且各列都有严重倾斜的表
版权所有© 2019 华为技术有限公司
HashVal
value0
value1
value2
……
value n
DN2

轮询 (RoundRobin) -- 8.1.3开始之后默认分布方式
哈希
T3
轮询
静态调优 - 分布列 – 选取原则
⚫
选择分布列的基本原则

列值应比较离散,以便数据能够均匀分布到各个DN
通常选择表的主键为分布列。
示例:人员信息表,选择身份证号作为分布列。

尽量不要选取存在常量等值过滤条件,避免DN剪枝后Scan集中到一个DN上。
示例:如果表dwcjk相关查询中经常出现dwcjk的列zqdh 存在常量的约束(例如zqdh= '000001'),则应尽量
不用 zqdh做分布列。
第29页

选择查询中的连接条件为分布列,以便Join任务能够下推到DN中执行,且减少DN间的通信数据量

根据上述原则尽量根据业务特征选择hash分布方式,无法确定时可以选择roundbobin分布
版权所有© 2019 华为技术有限公司
静态调优 - 分布列 – 倾斜分析和分布调整
⚫
判断数据是否存在存储倾斜的方法:table_distribution函数


⚫
示例
postgres=# SELECT * FROM pg_catalog.table_skewness('public.t1', 'b');
seqnum | num | ratio
--------+-----+--------3
| 260 | 26.000%
seqnum: DN的编号,dn_6001_6002编号为1,dn_6003_6004编号为2…
2
| 251 | 25.100%
二个入参可以是多个列表示组合分布列,多列之间使用逗号分隔,比如’a, b’
1
| 248 | 24.800%
0
| 241 | 24.100%
(4 rows)
调整分布列:alter语法

第30页
示例
postgres=# SELECT * FROM pg_catalog.table_distribution('public.t1');
schemaname | tablename |
nodename
| dnsize
------------+-----------+--------------+-------dnsize:单位为字节
public
| t1
| dn_6001_6002 |
8192
public
| t1
| dn_6003_6004 |
8192
public
| t1
| dn_6005_6006 | 98304
public
| t1
| dn_6007_6008 |
8192
(4 rows)
在线判定列是否倾斜:table_skewness函数

⚫
不同DN的数据量:相差5%以上即可视为倾斜;相差10%以上,建议调整分布列。
示例
ALTER TABLE public.t1 DISTRIBUTE BY HASH(b);
-- b 是修改后的分布列
ALTER TABLE public.t1 DISTRIBUTE BY REPLICATION;
ALTER TABLE public.t1 DISTRIBUTE BY ROUNDROBIN;
版权所有© 2019 华为技术有限公司
静态调优 - 选择分布列 - 典型案例
⚫
常见场景
a) 原始表定义存在数据倾斜,需要通过调整分布列达到数据分区均衡的目标
b) 把表分布列修改为关联列,达到性能加速的目的
c) 不同分布方式之间进行修改,比如把维度表调整成复制分布
⚫
分布列是订单号的执行计划:A-time = 4085ms
示例
SELECT
查询下订单的客户数据
count(distinct c_custkey)
FROM customer
WHERE c_custkey IN (
SELECT DISTINCT o_custkey
FROM orders_custkey
);
分布列是客户编号的执行计划:A-time = 3188ms ! 性能更优 !
原orders表的分布列为订单号o_orderkey
orders_custkey表为调整分布列为客户编号o_custkey
ALTER TABLE orders DISTRIBUTE BY HASH(o_custkey)
第31页
版权所有© 2019 华为技术有限公司
静态调优 - 局部聚簇 - 简述
⚫
局部聚簇 (Partial Cluster Key, 简称PCK)

⚫
⚫
⚫
适用场景
更多信息
点这里!

业务特征:大表大批量数据导入,每次导入数据量远大于DN数 * 6W

基表存在大量形如col op Const约束,其中col为列名,const为常量值,op为操作符 =、>、>=、<=、<

选用选择度比较高的简单表达式的列上建pck
使用约束

列存表,一个表只能创建一个PCK

适用数据类型有整型、时间类型、字符串类型

对于字符串类型,如果当前库的collate不为C,则只对表达式col = Const起大加速查询的效果
使用方法

第32页
列存储下一种通过min/max稀疏索引实现基表快速扫描的一种索引技术
创建表时指定PCK约束,或者ALTER TABLE语法增加PCK约束(只对后续导入数据生效)
版权所有© 2019 华为技术有限公司
静态调优 - 局部聚簇 - 优化原理
优化原理:入库时候进行局部排序换查询性能
物理存储
1001
CU边界值: 1
1002
60000
1003
120000
1004
180000
入 库 前 先 局 部 排 序 (420w
360000
420000
min
max
row_count
2
1001
1
60000
60000
写入cudes表(创建列存表时内置创建的
2
1002
60001
120000
60000
表,用来记录CU描述信息)
2
1003
120001
180000
60000
2
1004
180001
240000
60000
2
1005
240001
300000
60000
执行
2
1006
300001
360000
60000
执行过滤条件b = 100000时,首先可以根据cudes中该列的记录,进
2
1007
360001
420000
60000
示例
列存会同步把每个CU的最大值和最小值
行边界值校验(RougCheck),直接过滤掉除了1002之外的所有CU,然
后只从磁盘上扫描cu_id为1002,从而降低scan数据量
第33页
300000
1007
cu_id
SELECT * FROM t2 WHERE b = 100000

240000
1006
col_id
条),然后写到存储介质

1005
版权所有© 2019 华为技术有限公司
典型案例 - 局部聚簇 - 典型案例
普通表的执行计划:A-time = 314.498ms
⚫
测试场景
查询订单号为13095143的订单信息
PCK表的执行计划:A-time = 247.998ms! 性能更优!
第34页
版权所有© 2019 华为技术有限公司
CUNone比列越高,PCK效果越明显
静态调优 - 分区表 - 简述
⚫
分区表

把逻辑上的一个大表按照某种策略分成几块物理块进行存储时,逻辑上的大表称为分区表,每个物理块则称
为一个分区。


第35页
在查询时,通过分区剪枝技术尽可能减少底层数据扫描。
◼
改善查询性能
◼
增强可用性
◼
方便维护
适用场景
◼
数据规模:大表
◼
业务特征:通过剪枝缩小查询范围

分区键的选择:可以将数据均匀映射到各个分区的列,常见的分区键一般是时间列

支持Range分区表和List分区表
版权所有© 2019 华为技术有限公司
静态调优 - 分区表 - 典型案例
⚫
普通表的执行计划:A-time = 314.498ms
测试场景
统计1996年后的订单数
SELECT count(*) FROM orders WHERE
o_orderdate >= '1996-01-01 00:00:00'::timestamp(0);
分区表的执行计划:A-time = 168.338ms! 性能更优!
第36页
版权所有© 2019 华为技术有限公司
Iterations越小,分区剪枝效果越好
本节小结
⚫
本节主要从表定义角度,介绍静态调优的几种常用方法,从而指导用户根据业务场
景正确选择表的存储类型、分布方式和分布列,合理使用局部聚簇、分区表来设计
和定义表,提高SQL语句的查询性能。
⚫
更多内容,请访问
https://bbs.huaweicloud.com/blogs/203219
https://bbs.huaweicloud.com/blogs/175458
第37页
版权所有© 2019 华为技术有限公司
目录
1. Explain执行计划
2. 调优原则
3. 调优流程
4. 静态调优
5. 动态调优
第38页
版权所有© 2019 华为技术有限公司
动态调优 - 查询执行流程
⚫
词法&语法解析

⚫
⚫
格式化结构(Stmt)转化为数据库可以识别的对象。
语义解析
根据规则将“语义解析”的输出等价转化为执行上更为优化的结构。
查询优化

根据“查询重新”的输出和数据库内部的统计信息规划SQL语句具体的执行方式。
查询执行

SQL语句
语法&语法解析
查询重写

⚫
SQL 重写
语义解析

⚫
按照约定的SQL语句规则,将输入的SQL语句从字符串转化为格式化结构(Stmt)。
Plan Hint
根据“查询优化”规划的执行路径执行SQL查询语句。
统计信息
GUC参数
底层存储
查询重写
查询优化
查询执行
输出结果
第39页
版权所有© 2019 华为技术有限公司
动态调优 - 计划生成
⚫
执行计划三要素



⚫
表的元组数、字段宽度、NULL记录比率、DISTINCT值、MCV值 (Most Common Value)
◼
HB值 (直方图,数据分布概率区间)
优化器 (基于代价的优化 (Cost-Based Optimization,简称CBO )
◼
数据库根据大量表数据特征,结合代价计算模型,通过代价估算输出估算的最优执行计划
◼
统计信息是查询优化的核心输入,准确的统计信息可以帮助优化器选择最合适的查询计划
配置参数
◼
这个说的配置参数包括GUC参数和hint信息
◼
配置参数直接干预优化器路径选择
使用ANALYZE语法收集整个表或表的若干列的统计信息
如何操作

第40页
◼
统计信息如何收集?

⚫
统计信息 (表数据特征)
大批量数据导入/更新/删除之后及时analyze
版权所有© 2019 华为技术有限公司
动态调优 - 调优流程
⚫
概述
START
动态调优,即执行态调优,是一个不断分析与尝试的过程。
SQL试跑
首先,试跑Query;然后,判断性能是否满足客户需求;
如果不满足客户需求,则需要进一步分析性能瓶颈点;
获取性能瓶颈点之后进行针对性优化,重新试跑,一直到满足性能目标。
⚫
END
Yes
性能OK
No
统计信息分析
基本步骤

判断查询相关表是否已收集统计信息

判断查询语句是否下推

收集Perfromance信息进行性能分析,并做针对性优化

SQL改写优化
不下推分析
performance分析
SQL改写/修改配置
资源消耗分析
SQL优化
第41页
版权所有© 2019 华为技术有限公司
性
能
瓶
颈
分
析
动态调优 - 批量慢SQL识别
⚫
基于topSQL的慢SQL识别
topSQL记录了查询作业运行结束时的资源使用情况(包括内存、下盘、CPU时间、IO等)和运行状态信息(包括报
错、终止、异常等)以及性能告警信息
resource_track_level典型配置型
query:记录语句的计划信息(类似explain输出信息)
perf:记录类似explain analyze的实际执行时间和执行行数的计划信息

GUC参数enable_resource_track为on (默认为on)

GUC参数resource_track_level为query、perf或operator(默认为query)

GUC参数enable_resource_record为on(默认为off)

GUC参数resource_track_duration小于作业执行时间(默认为60s)

GUC参数resource_track_cost(默认为100000)
配置建议
1. 所有环境 enable_resource_record设置为on
2. 测试集群、联调期间resource_track_level设置为perf;生产进群和性能压
测环境resource_track_level设置为query
SELECT queryid,
start_time,
duration, -- 执行时间
warning, -- SQL自诊断信息
query, -- SQL语句
query_plan -- SQL语句简单的explain
FROM pgxc_wlm_session_info
WHERE username = 'edw_poc' -- 用户
AND dbname = 'pluat' -- 数据库
AND duration > 10000 -- 长SQL阈值,单位ms
AND start_time BETWEEN now() AND (now() - interval '1 days') --SQL时间段
ORDER BY duration DESC -- 按照执行时长倒序输出
LIMIT 100; -- top 100
第42页
版权所有© 2019 华为技术有限公司
动态调优 - 统计信息 - 典型案例
⚫
收集统计信息前后执行计划对比分析

未做Analyze的执行计划:E-rows小,Nest Loop
E-rows:
没有收集统计信息的计划中,估计值E-rows比实际值小

执行计划:
没有收集统计信息的计划中,出现两个低效的Nest Loop算子

示例:
查询所有供货商在1994年1月1日起的1年间为公司带来的总收入。
SELECT
sum(l_extendedprice * (1 - l_discount)) AS revenue
FROM customer, orders, lineitem,supplier
WHERE c_custkey = o_custkey
AND l_orderkey = o_orderkey
AND l_suppkey = s_suppkey
AND o_orderdate >= '1994-01-01'::date
AND o_orderdate < '1994-01-01'::date + interval '1 year';
第43页
版权所有© 2019 华为技术有限公司
做完Analyze的执行计划!
动态调优 - 不下推分析 - 计划类型
⚫
并行计算能力是GaussDB(DWS)的性能优势
⚫
优化器在分布式框架下有三种执行规划策略

下推语句计划
CN发送查询语句到DN直接执行,执行结果返回给CN。
特征:__REMOTE_FQS_QUERY__

分布式计划
CN生成计划树,发送计划树给DN执行;
DN执行完后,将结果返回给CN。
特征:Streaming (type:GATHER)

不下推计划:CN承载大量计算任务,导致性能劣化!
优化器将部分查询(多为基表扫描语句)
下推到DN进行执行,将获取的中间结果发给CN,
CN再执行计划剩下的部分。
特征:REMOTE_XXX+Coordinator quals
第44页
版权所有© 2019 华为技术有限公司
动态调优 - 不下推分析 - 识别不下推
⚫
常见的不下推因素

⚫
含有shippable属性为false的函数的语句不下推
不下推问题定位手段

EXPLAIN PERFORMANCE/EXPLAIN VERBOSE
对于当前正在执行的SQL,可以通过EXPLAIN PERFORMANCE或者EXPLAIN VERBOSE输出信息中的SQL Diagnostic
Information部分会提示具体的不下推的原因

Top SQL
历史执行SQL信息会被记录到系统表中,我们可以在postgres库中查询视图pgxc_wlm_session_info获取历史SQL的执行信息,
此表的warning字段会记录对应SQL语句的
第45页
版权所有© 2019 华为技术有限公司
动态调优 - 不下推分析 - 函数易变属性
⚫
函数下推行为的分析

函数的易变属性可分为三种,在创建函数时如果不指定函数易变属性,默认为VOLATILE
◼
IMMUTABLE:相同的入参值,总是返回相同的结果。如,pg_catalog.trunc(numeric)
◼
STABLE:相同的入参值,同一次表扫描中,函数返回值不变,但在不同SQL语句中函数返回值可能发生变化。通常,此
类函数的输出值受到环境变量的影响,但一条SQL语句执行过程中,此环境变量不会发生变化。如,pg_catalog.now()
◼
VOLATILE:相同的入参值,函数值随时可能返回不同的结果,即便是同在一次表扫描内。如,pg_catalog.random(

函数定义时可指定函数下推属性为SHIPPABLE,默认为NOT SHIPPABLE,即调用函数的SQL语句不下推。

函数的下推行为由其易变属性和下推属性共同决定。
易变属性
IMMUTABLE
STABLE
VOLATILE
SHIPPABLE
下推
下推
下推
NOT SHIPPABLE
下推
不下推
不下推
下推属性
第46页
函数创建 CREATE FUNCTION
版权所有© 2019 华为技术有限公司
函数修改 ALTER FUNCTION
动态调优 - Performance分析
⚫
Explain Performance:收集Query的执行信息 + 分析可能的性能问题 + 针对性优化
⚫
重点关注:耗时占整体执行时间高的算子
⚫
重要执行信息:DataNode Information、Memory Information、Targetlist Information
⚫
常见算子的瓶颈及优化策略



Scan性能瓶颈
◼
基表扫描元组数过多:增加索引、使用PCK、使用分区
◼
数据在各个DN分布不均衡:调整分布列方式
Join性能瓶颈
◼
Join方式选择不当:增加索引、使用Plan Hint
◼
Join内外表选择不当:使用Plan Hint、改写SQL
Subplan性能瓶颈
◼
第47页
Subplan比Join性能差,建议改写Subplan为Join
版权所有© 2019 华为技术有限公司
动态调优 - Scan性能优化
⚫
Scan性能提升策略
◼
减少实际IO
◼
点查场景:增加索引;使用PCK (列存表)
示例:查询编号为1106459顾客的订单信息
◼
◼
范围查询场景:分区 (优化IO)
把Scan压力分散到各个DN上:数据倾斜,IO压力分布不均衡!Performance信息中各DN的扫描时间存在明显差异!
◼
第48页
创建索引后:性能优化!
优化策略:修改分布列
版权所有© 2019 华为技术有限公司
动态调优 - Join性能优化 - Join类型
⚫
表连接 (Join):根据特定规则从两个其他表 (真实表或生成表)中派生出结果集

Join语法
T1 Join_type T2 [join_condition]
T1和T2都可以是连接生成的表,支持多层嵌套。使用括号”()”控制连接顺序,否则,自左向右逐层嵌套。

Join类型
◼
语法层支持:内连接 (Inner Join)、外连接 (Outer Join) 和交叉连接 (或笛卡尔积,Cross Join)
T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 ON boolean_expression
T1 { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2 USING ( join column list )
T1 NATURAL { [INNER] | { LEFT | RIGHT | FULL } [OUTER] } JOIN T2
INNER是缺省的,LEFT、RIGHT和FULL都是外连接,连接条件在ON或USING子句中指定。
◼
第49页
内置实现支持:半连接 (Semi Join,IN约束转化生成)、反半连接 (Anti Join,NOT IN约束转化生成)
版权所有© 2019 华为技术有限公司
动态调优 - Join性能优化 - Join类型
⚫
SEMI JOIN(匹配上即命中)
SELECT * FROM score t1 WHERE EXISTS (SELECT 1 FROM student t2 WHERE t1.sno = t2.sno);
⚫
sno
cname
Grade
1
english
90
2
english
95
1
math
100
ANTI JOIN(匹配上即排除)
SELECT * FROM score t1 WHERE NOT EXISTS (SELECT 1 FROM student t2 WHERE t1.sno = t2.sno);
第50页
版权所有© 2019 华为技术有限公司
sno
cname
Grade
4
chinese
88
动态调优 - Join性能优化 - 优化策略
⚫
Join性能提升策略

HashJoin性能最好!
策略1:选择高效的Join方式
◼
支持的Join方式:HashJoin、MergeJoin、NestLoop
◼
通常情况下,HashJoin较为高效的
◼
部分特定场景下,Nestloop + IndexScan性能更好
满足条件:① Inner Join;② Join条件为简单等值表达式;③ Outer分支输出结果集特别少;④ Inner分支只有表Scan,
且Join条件相关列有索引。
示例:查询指定用户的用户信息及其所有订单信息
满足条件①②③,表Order的顾客编号列已创建索引。
第51页
版权所有© 2019 华为技术有限公司
动态调优 - Join性能优化 - 优化策略
⚫
Join性能提升策略

策略1:选择高效的Join方式
◼
改写SQL实现HashJoin
优化策略:尝试将不等值Join条件转化为等值Join条件
--原用例。
SELECT
t8.*
FROM loan_info t8
INNER JOIN acc_loan tt ON
(tt.account = t8.lncfno or tt.billno = t8.lncfno)
WHERE t8.loantp <> 'XXXX';
第52页
版权所有© 2019 华为技术有限公司
-- 等价改写后用例。
WITH TT as
(
select account as val from acc_loan
union all
select billno as val from acc_loan
)
SELECT
t8.*
FROM loan_info t8
INNER JOIN tt ON (tt.val = t8.lncfno)
WHERE t8.loantp <> 'XXXX';
动态调优 - Join性能优化 - 优化策略
⚫
Join性能提升策略

策略2:选择合适的内外表
◼
HashJoin:内表小,外表大,执行高效!
◼
使用Plan Hint调整内外表顺序
-- 原用例。
SELECT
c_name, c_address,c_phone, o_orderkey, o_orderstatus
FROM customer c JOIN orders o ON o_custkey = c_custkey
WHERE c_name IN ('Customer#000000001', 'Customer#000000002');
示例:查询指定用户的用户信息及用户的订单信息
分析:订单表order数据量较大,用户表customer经过filter过滤只有2条记录;走HashJoin,表customer做内表性能好。
结论:订单表order做外表,用户表customer做内表,性能更优!
SELECT
/*+ hashjoin(o c) leading((o c)) tablescan(o) */
…
第53页
版权所有© 2019 华为技术有限公司
SELECT
/*+ hashjoin(o c) leading((o c)) tablescan(c) */
…
动态调优 - plan hint - 语法简介
⚫
plan hint为用户提供直接影响执行计划生成的手段,通过对执行计划的调优,提升查询的性能。
⚫
常用hint调优手段
⚫

指定scan方法

指定join方法、join顺序和join时的stream策略

指定估算行数

指定重分布过程中的倾斜信息

配置参数的hint
功能描述
-- 查询尚未运送的金额在前10位的订单
SELECT
l_orderkey, o_shippriority
sum(l_extendedprice * (1-l_discount)) AS revenue,
FROM customer, orders, lineitem
WHERE c_mktsegment = 'BUILDING' AND c_custkey = o_custkey
AND l_orderkey = o_orderkey
GROUP BY l_orderkey, o_shippriority
ORDER BY revenue desc
limit 10;

plan hint仅支持在SELECT关键字后通过如下形式指定:

可以同时指定多个hint,不同hint信息使用空格分隔

配置参数之外的hint只能hint当前层的计划,对于子查询计划的hint ,需要在子查询的SELECT关键字后指定hint信息
SELECT /*+ <planhint1> <planhint2> */ FROM t1, (SELECT /*+ <planhint3> */ FROM t2) WHERE 1=1;
第54页

在视图定义时指定hint,该视图每次被调用时都会使用该hint信息

表只能用单个字符串表示,不能带schema;表如果存在别名,需要优先使用别名来表示该表。
版权所有© 2019 华为技术有限公司
动态调优 - plan hint - hint扫描方式

语法格式
[no] tablescan|indexscan|indexonlyscan(table [index])

◼
no表示hint的scan方式不使用
◼
table表示hint指定的表,只能指定一个表,如果表存在别名应优先使用别名进行hint
◼
index表示使用indexscan或indexonlyscan的hint时,指定的索引名称,当前只能指定一个
示例:查询尚未运送的金额在前10位的订单
CREATE INDEX idx_l on lineitem(l_orderkey);
EXPLAIN SELECT /*+ indexscan(lineitem idx_l)*/
……
Hint指定IndexScan时,
表lineitem的扫描采用
Cstore Index Scan.
原计划采用Cstore Scan
第55页
版权所有© 2019 华为技术有限公司
动态调优 - plan hint - hint关联方式

语法格式
[no] nestloop|hashjoin|mergejoin(table_list)

◼
可选项 no表明hint指定的Join方法不使用
◼
table_list:hint表集合的字符串,中间不允许出现括号指定Join的优先级
示例:查询尚未运送的金额在前10位的订单
SELECT /*+ nestloop(lineitem customer orders)*/
… …
Hint指定join方式时,表
lineitem、orders先
hashjoin,再与customer
做nestloop
表orders、customer先hashjoin,
再与lineitem作hashjoin
第56页
版权所有© 2019 华为技术有限公司
动态调优 - plan hint - hint关联顺序
⚫
语法格式

仅指定join顺序,不指定内外表顺序。
leading(join_table_list)

同时指定join顺序和内外表顺序,内外表顺序仅在最外层生效。
leading((join_table_list))
⚫
第57页
示例:尚未运送的金额在前10位的订单
版权所有© 2019 华为技术有限公司
动态调优 - plan hint – hint估算行数

语法格式
rows(table_list #|+|-|* const)

◼
支持#,+,-,*四种操作符;#表示直接使用后面的行数替换优化器的估算行数,+,-,*表示对原来估算的行数进行加、减、乘操作
◼
运算后的行数最小值为1行。table_list为hint对应的单表或多表join结果集,与join的hint中table_list相同。
◼
const可以是任意非负数,支持科学计数法
支持绝对值和相对值的hint。常用于多表join时,中间结果集估算表不准的场景。
SELECT /*+ rows(lineitem customer orders #5) */
… …
Hint指定rows hint
时,三表join结果集
函数为5
原计划join后结果集的行数
第58页
版权所有© 2019 华为技术有限公司
动态调优 - plan hint – hint stream

语法格式
[no] broadcast|redistribute(table_list)

◼
no表示hint的stream方式不使用
◼
table_list为进行stream操作的单表或多表join结果集
建议: Stream Hint和Join Hint配合使用,先hint明确join顺序,然后hint明确中间结果集的数据流动方式
SELECT /*+ no redistribute (lineitem orders) nestloop(lineitem customer orders)*/
… …
Hint指定no redistribute
时,禁止join过程做重分布,
join顺序不变。
Hint指定join方式为
nestloop时,Join过
程做了重分布
第59页
版权所有© 2019 华为技术有限公司
动态调优 - SQL改写 - 相关子链接改写
⚫
子查询和子链接性能较差
⚫
大部分场景,可提升为Join进行优化;小部分场景,需要用户改写SQL进行优化

改写策略:在语义等价前提下,将子链接、子查询的查询语句提升到外层查询进行关联查询

示例:查询指定用户的消费额度和每单消费平均额
SELECT
c_name,
(SELECT
sum(o_totalprice)
FROM orders o
WHERE o.o_custkey=c.c_custkey)
FROM
customer c
WHERE c_name
IN('Customer#000000001', 'Customer#000000002');
第60页
版权所有© 2019 华为技术有限公司
子查询提升到外层查询后性能更优!
WITH o AS (
SELECT
sum(o_totalprice) AS sum, o_custkey
FROM orders
GROUP BY o_custkey
)
SELECT
c_name, sum
FROM customer c
LEFT JOIN o ON o.o_custkey = c.c_custkey
WHERE c_name
IN('Customer#000000001', 'Customer#000000002');
动态调优 - SQL改写 - join条件改写
⚫
等值Join条件的Join列增加非空过滤条件

适用场景
等值Join,且Join列存在大量的NULL


优化原理
◼
NULL值和任何值比较的结果都是NULL
◼
通过给关联列增加IS NOT NULL,降低基表扫描输出的数据量,从而减小参与JOIN运算的数据量
改写方式
假设表t1和表t2存在等值连接 t1.a = t2.a
Join方式
第61页
增加FILTER条件
t1 INNER JOIN t2 ON t1.a = t2.a
t1.a IS NOT NULL AND t2.a IS NOT NULL
t1 LEFT JOIN t2 ON t1.a = t2.a
t2.a IS NOT NULL
t1 RIGHT JOIN t2 ON t1.a = t2.a
t1.a IS NOT NULL
版权所有© 2019 华为技术有限公司
动态调优 - SQL改写 - NOT IN改写
⚫
NOT IN转NOT EXISTS

适用场景
子链接输出列上不存在NULL值,或者逻辑判断语义上不需要比较NULL值
示例:t2.c2和t1.c2列不存在NULL值
SELECT * FROM t1 WHERE t1.c1 NOT IN (SELECT t2.c2 FROM t2);

第62页
优化原理
◼
只输出WHERE条件为true的结果
◼
NULL和任何值的比较操作均为NULL
◼
NULL和bool类型的逻辑运算
版权所有© 2019 华为技术有限公司
动态调优 - SQL改写 - NOT IN改写
⚫
NOT IN逻辑解析
➢
t1.c2 NOT IN (SELECT t2.c2 FROM t2)
➢
<=> NOT (t1.c2 IN (SELECT t2.c2 FROM t2))
➢
<=> (t1.c2 IN (SELECT t2.c2 FROM t2)) = false
因为NULL值跟任意值的OR运算结果都是NULL,上述条件表达式等价于
t1.c2 <> ANY(t2.c2) AND t1.c2 IS NOT NULL AND ANY(t2.c2) IS NOT NULL
⚫
NOT EXISTS逻辑解析
➢
NOT EXISTS (SELECT 1 FROM t2 WHERE t1.c1=t2.c2)
➢
<=> 'SELECT 1 FROM t2 WHERE t1.c1=t2.c2' 输出0条记录
➢
<=> t1.c1= ANY(t2.c2) 结果为false或者NULL
➢
<=> t1.c2 IS NULL OR t1.c2 <> ANY(t2.c2)
当 t1.c2 IS NOT NULL AND t2.c2 IS NOT NULL
恒成立时,NOT IN和NOT EXISTS等价
第63页
版权所有© 2019 华为技术有限公司
本节小结
⚫
本节简要介绍动态调优的基本流程,常用的统计信息及其收集方法,如何根据执行
信息分析SQL语句的性能瓶颈,并着重介绍因计划不下推造成性能问题的典型场景
及优化策略。
第64页
版权所有© 2019 华为技术有限公司
Download