数据库性能调优 版权所有© 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 华为技术有限公司