PolarDB-X性能优化之执行计划基础

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云原生数据库 PolarDB 分布式版,标准版 2核8GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 介绍一下PolarDB-X的执行计划及如何查看执行计划

1 执行计划基本概念

     使用PolarDB-X时,应用程序的查询SQL(称为逻辑SQL)发往PolarDB-X计算节点(CN),PolarDB-X会将其分成可下推的、和不可下推的两部分,可下推的部分也被称为物理SQL。不可下推的SQL在CN上执行,下推的SQL在DN上执行。

    PolarDB-X在查询优化过程中尽可能将用户SQL下推到DN上执行,避免CN和DN间数据网络交互以外,同时充分利用多分片并发执行的能力,利用各个DN资源,加速查询。可以下发给DN的算子包括LogicalView,LogicalModifyView,PhyTableOperation, IndexScan,对于语句其它无法下推的部分,优化器会选择最优的方式来执行,比如选择合适的算子执行、选择合适的并行度策略以及是否使用 MPP 执行。

   对于PolarDB-X的执行计划,下面的基础概念需要了解

   a) 逻辑SQL: 用户侧发起的查询SQL;

   b) 物理SQL:SQL经过查询优化后,一般会拆分为可下推和不可下推的SQL,其中可下推的SQL是发往DN执行的,叫物理SQL。如果逻辑SQL被全部下推到DN执行,那么物理SQL等价于逻辑SQL。

   PolarDB-X的explain命令提供了比较多的选项,可以从各个不同的角度查看和分析执行计划。

2 实例sql语句

MySQL [test]> select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b

                where a.dept_no=b.dept_no  and b.dept_no=30  

                 group by a.dept_no, b.dept_name;

+---------+--------------+---------------+

| dept_no | dept_name    | sum(a.salary) |

+---------+--------------+---------------+

|      30 | 进出口部     |          1375 |

+---------+--------------+---------------+

1 row in set (0.09 sec)

本文中使用上述sql语句示范从不同角度使用explain的不同选项查看执行计划。

3 查看逻辑执行计划

MySQL [test]> explain select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b

                     ->  where a.dept_no=b.dept_no  and b.dept_no=30

                     ->   group by a.dept_no, b.dept_name;

     +-----------------------------------------------------------------------------------+

     | LOGICAL EXECUTIONPLAN    |

     +-----------------------------------------------------------------------------------+

     | HashAgg(group="dept_no,dept_name", sum(a.salary)="SUM(salary)") |

     |   Project(dept_no="dept_no0", salary="salary", dept_no0="dept_no",   dept_name="dept_name")                                                                     |

     |     BKAJoin(condition="dept_no = dept_no", type="inner")             |

     |       LogicalView(tables="dept[p11]", sql="SELECT `dept_no`, `dept_name` FROM `dept` AS `dept` WHERE (`dept_no` = ?)")                                      |

     |       Gather(concurrent=true)  |

     |         LogicalView(tables="emp[p1,p2]", shardCount=2, sql="SELECT `dept_no`, `salary` FROM `emp` AS `emp` WHERE ((`dept_no` = ?) AND (`dept_no` IN (...)))") |

     | HitCache:true  |

     | Source:PLAN_CACHE |

     | TemplateId: 466da528  |

     +--------------------------------------------------------------------------------+

     9 rows in set (0.01 sec)

   使用不带任何选项的explain命令可以查看sql语句的逻辑执行计划,这条有两个LogicalView算子可以下推到dn节点执行,CN节点先做bkajoin,然后做哈希聚合。

  如果想看优化器对每一步的估算成本,使用cost选项

MySQL [test]> explain cost  select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b                  where a.dept_no=b.dept_no  and b.dept_no=30                    group by a.dept_no, b.dept_name;

     +-----------------------------------------------------------------------------------+

     | LOGICAL EXECUTIONPLAN                                                                             |

     +-----------------------------------------------------------------------------------+

     | HashAgg(group="dept_no,dept_name", sum(a.salary)="SUM(salary)"): rowcount = 1.0, cumulative cost = value = 1.0015027E7, cpu = 27.0, memory = 199.0, io = 3.0, net = 2.0                                                                                       |

     |   Project(dept_no="dept_no0", salary="salary", dept_no0="dept_no", dept_name="dept_name"): rowcount = 1.0, cumulative cost = value = 1.0015012E7, cpu = 12.0, memory = 69.0, io = 3.0, net = 2.0                                                       |

     |     BKAJoin(condition="dept_no = dept_no", type="inner"): rowcount = 1.0, cumulative cost = value = 1.0015011E7, cpu = 11.0, memory = 69.0, io = 3.0, net = 2.0                                                                                                                       |

     |       LogicalView(tables="dept[p11]", sql="SELECT `dept_no`, `dept_name` FROM `dept` AS `dept` WHERE (`dept_no` = ?)"): rowcount = 1.0, cumulative cost = value = 5005002.0, cpu = 2.0, memory = 0.0, io = 1.0, net = 1.0                           |

     |       Gather(concurrent=true): rowcount = 1.0, cumulative cost = value = 5003.0, cpu = 3.0, memory = 0.0, io = 1.0, net = 0.0                                               |

     |         LogicalView(tables="emp[p1,p2]", shardCount=2, sql="SELECT `dept_no`, `salary` FROM `emp` AS `emp` WHERE ((`dept_no` = ?) AND (`dept_no` IN (...)))"): rowcount = 1.0, cumulative cost = value = 5002.0, cpu = 2.0, memory = 0.0, io = 1.0, net = 0.0                                                                                                        |

     | HitCache:true                                                                                               |

     | Source:PLAN_CACHE                                                                                    |

     | WorkloadType: TP                                                                                         |

     | TemplateId: 466da528                                                                                   |

     +-----------------------------------------------------------------------------------+

     10 rows in set (0.00 sec)

上面可以看到每一个算子的估算函数,累加成本,消耗的cpu、内存、IO。使用analyze选项,在看到优化器估算的成本之外,也可以看到每个算子实际执行的资源消耗

MySQL [test]> explain analyze  select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b                  where a.dept_no=b.dept_no  and b.dept_no=30                    group by a.dept_no, b.dept_name;

     +-----------------------------------------------------------------------------------+

     | LOGICAL EXECUTIONPLAN                                                                             |

     +-----------------------------------------------------------------------------------+

     | HashAgg(group="dept_no,dept_name", sum(a.salary)="SUM(salary)"): rowcount = 1.0, cumulative cost = value = 1.0015027E7, cpu = 27.0, memory = 199.0, io = 3.0, net = 2.0, actual time = 0.000 + 0.000, actual rowcount = 1, actual memory = 0, instances = 1                                                                                    |

     |   Project(dept_no="dept_no0", salary="salary", dept_no0="dept_no", dept_name="dept_name"): rowcount = 1.0, cumulative cost = value = 1.0015012E7, cpu = 12.0, memory = 69.0, io = 3.0, net = 2.0, actual time = 0.003 + 0.001, actual rowcount = 27, actual memory = 0, instances = 1                                                  |

     |     BKAJoin(condition="dept_no = dept_no", type="inner"): rowcount = 1.0, cumulative cost = value = 1.0015011E7, cpu = 11.0, memory = 69.0, io = 3.0, net = 2.0, actual time = 0.003 + 0.001, actual rowcount = 27, actual memory = 261876, instances = 1                                                                                                     |

     |       LogicalView(tables="dept[p11]", sql="SELECT `dept_no`, `dept_name` FROM `dept` AS `dept` WHERE (`dept_no` = ?)"): rowcount = 1.0, cumulative cost = value = 5005002.0, cpu = 2.0, memory = 0.0, io = 1.0, net = 1.0, actual time = 0.000 + 0.001, actual rowcount = 1, actual memory = 0, instances = 0                           |

     |       Gather(concurrent=true): rowcount = 1.0, cumulative cost = value = 5003.0, cpu = 3.0, memory = 0.0, io = 1.0, net = 0.0, actual time = 0.000 + 0.000, actual rowcount = 0, actual memory = 0, instances = 0                                          |

     |         LogicalView(tables="emp[p1,p2]", shardCount=2, sql="SELECT `dept_no`, `salary` FROM `emp` AS `emp` WHERE ((`dept_no` = ?) AND (`dept_no` IN (...)))"): rowcount = 1.0, cumulative cost = value = 5002.0, cpu = 2.0, memory = 0.0, io = 1.0, net = 0.0, actual time = 0.001 + 0.001, actual rowcount = 27, actual memory = 0, instances = 0 |

     | HitCache:true                                                                                                 |

     | Source:PLAN_CACHE                                                                                      |

     | TemplateId: 466da528                                                                                    |

     +----------------------------------------------------------------------------------+

     9 rows in set (0.05 sec)

从上面不但可以看到优化器估算的成本,也可以看到每个算子实际执行的时间,行数及内存。

使用physical选项可以看到sql语句执行的片段及片段之间的依赖关系

MySQL [test]> explain physical  select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b                  where a.dept_no=b.dept_no  and b.dept_no=30                    group by a.dept_no, b.dept_name;

     +-----------------------------------------------------------------------------------+

     | PLAN                                                                                                             |

     +-----------------------------------------------------------------------------------+

     | ExecutorMode: TP_LOCAL                                                               |

     | Fragment 0 dependency: [] parallelism: 1                                         |

     | Project(dept_no="dept_no0", salary="salary", dept_no0="dept_no", dept_name="dept_name")                                                                     |

     |   BKAJoin(condition="dept_no = dept_no", type="inner")                |

     |     LogicalView(tables="dept[p11]", sql="SELECT `dept_no`, `dept_name` FROM `dept` AS `dept` WHERE (`dept_no` = ?)")                                        |

     |     Gather(concurrent=true)                                                                           |

     |       LogicalView(tables="emp[p1,p2]", shardCount=2, sql="SELECT `dept_no`, `salary` FROM `emp` AS `emp` WHERE ((`dept_no` = ?) AND (`dept_no` IN (...)))") |

     | Fragment 1 dependency: [0] parallelism: 2                                                    |

     | HashAgg(group="dept_no,dept_name", sum(a.salary)="SUM(salary)")           |

     |   RemoteSource(sourceFragmentIds=[0], type=RecordType(INTEGER dept_no, BIGINT salary, TINYINT(3) dept_no0, VARCHAR(20) dept_name))                          |

     +-----------------------------------------------------------------------------------+

     10 rows in set (0.05 sec)

语句的执行分为两个片段,后面的哈希聚合片段依赖前面的投影、bkaJoin片段。

4 物理执行计划查看

查看物理执行计划使用execute选项,看到的是语句在dn节点执行部分的MySQL执行计划。

explain execute select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b  where a.dept_no=b.dept_no  and b.dept_no=30                    group by a.dept_no, b.dept_name\G;

*************************** 1. row ***************************

          id:

 select_type: SIMPLE

       table: dept

  partitions: NULL

        type: const

possible_keys: PRIMARY

         key: PRIMARY

     key_len: 1

         ref: const

        rows:

    filtered: 100

       Extra: NULL

*************************** 2. row ***************************

          id:

 select_type: SIMPLE

       table: emp

  partitions: NULL

        type: ALL

possible_keys: NULL

         key: NULL

     key_len: NULL

         ref: NULL

        rows:       ▒

    filtered: 9.999999046325684

       Extra: Using where

2 rows in set (0.05 sec)

ERROR: No query specified


4 索引推荐

explain的advisor选项可以为sql语句推荐合适的索引及表的分区形式。

MySQL [test]> explain advisor  select a.dept_no,b.dept_name, sum(a.salary) from emp a, dept b                  where a.dept_no=b.dept_no  and b.dept_no=30                    group by a.dept_no, b.dept_name\G;

*************************** 1. row ***************************

IMPROVE_VALUE: 99.6%

 IMPROVE_CPU: 207.2%

 IMPROVE_MEM: 51.3%

  IMPROVE_IO: -33.3%

 IMPROVE_NET: 100.0%

BEFORE_VALUE: 1.00100228E7

  BEFORE_CPU: 22.7

  BEFORE_MEM: 140.8

   BEFORE_IO: 2

  BEFORE_NET: 2

 AFTER_VALUE: 5015007.4

   AFTER_CPU: 7.3

   AFTER_MEM: 93

    AFTER_IO: 3

   AFTER_NET: 1

ADVISE_INDEX: ALTER TABLE test.emp BROADCAST; ALTER TABLE test.dept BROADCAST;

    NEW_PLAN:

Gather(concurrent=true)

 LogicalView(tables="emp,dept", shardCount=0, sql="SELECT `emp`.`dept_no`, `dept`.`dept_name`, SUM(`emp`.`salary`) AS `sum(a.salary)` FROM `emp` AS `emp` INNER JOIN `dept` AS `dept` ON (((`dept`.`dept_no` = ?) AND (`emp`.`dept_no` = `dept`.`dept_no`)) AND (`emp`.`dept_no` = ?)) GROUP BY `emp`.`dept_no`, `dept`.`dept_name`")

        INFO: BROADCAST

1 row in set (0.18 sec)

ERROR: No query specified

这里推荐是将这两个表都改为广播表。






相关实践学习
快速体验PolarDB开源数据库
本实验环境已内置PostgreSQL数据库以及PolarDB开源数据库:PolarDB PostgreSQL版和PolarDB分布式版,支持一键拉起使用,方便各位开发者学习使用。
相关文章
|
6月前
|
监控 关系型数据库 分布式数据库
【PolarDB 开源】PolarDB HTAP 实践:混合事务与分析处理的性能优化策略
【5月更文挑战第21天】PolarDB开源后在HTAP领域表现出色,允许在同一系统处理事务和分析工作负载,提高数据实时性。通过资源分配、数据分区、索引优化等策略提升性能。示例代码展示了创建和查询事务及分析表的基本操作。PolarDB还提供监控工具,帮助企业优化系统并应对业务变化。其HTAP能力为开发者和企业提供了强大支持,推动技术进步,加速数字化时代的业务发展。
435 1
|
3月前
|
存储 算法 Cloud Native
【PolarDB-X列存魔法】揭秘TPC-H测试背后的性能优化秘籍!
【8月更文挑战第25天】阿里巴巴的云原生数据库PolarDB-X以其出色的性能、可靠性和扩展性闻名,在多种业务场景中广泛应用。尤其在列存储模式下,PolarDB-X针对分析型查询进行了优化,显著提升了数据读取效率。本文通过TPC-H基准测试探讨PolarDB-X列存执行计划的优化策略,包括高效数据扫描、专用查询算法以及动态调整执行计划等功能,以满足复杂查询的需求并提高数据分析性能。
92 1
|
4月前
|
SQL 关系型数据库 分布式数据库
PolarDB产品使用问题之主节点和列存节点的执行计划相同,而只读行存节点的执行计划不同,是什么原因
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
5月前
|
运维 关系型数据库 Serverless
PolarDB产品使用问题之什么原因导致执行计划不一致
PolarDB产品使用合集涵盖了从创建与管理、数据管理、性能优化与诊断、安全与合规到生态与集成、运维与支持等全方位的功能和服务,旨在帮助企业轻松构建高可用、高性能且易于管理的数据库环境,满足不同业务场景的需求。用户可以通过阿里云控制台、API、SDK等方式便捷地使用这些功能,实现数据库的高效运维与持续优化。
|
5月前
|
关系型数据库 分布式数据库 数据库
PolarDB产品使用合集之可以使用什么来查看查询的执行计划和性能信息
PolarDB是阿里云推出的一种云原生数据库服务,专为云设计,提供兼容MySQL、PostgreSQL的高性能、低成本、弹性可扩展的数据库解决方案,可以有效地管理和优化PolarDB实例,确保数据库服务的稳定、高效运行。以下是使用PolarDB产品的一些建议和最佳实践合集。
113 0
|
6月前
|
关系型数据库 MySQL 分布式数据库
PolarDB auto_inc场景下的性能优化实践
PolarDB auto_inc场景下的性能优化实践 在数据库的使用场景中,并发插入数据或并发导入数据场景是最常见的。针对这一场景,PolarDB MySQL版进行了深度性能优化,以提高插入性能。本文将详细介绍PolarDB在auto_inc场景下的性能优化相关内容。
87 2
|
关系型数据库 测试技术 分布式数据库
PolarDB | PostgreSQL 高并发队列处理业务的数据库性能优化实践
在电商业务中可能涉及这样的场景, 由于有上下游关系的存在, 1、用户下单后, 上下游厂商会在自己系统中生成一笔订单记录并反馈给对方, 2、在收到反馈订单后, 本地会先缓存反馈的订单记录队列, 3、然后后台再从缓存取出订单并进行处理. 如果是高并发的处理, 因为大家都按一个顺序获取, 容易产生热点, 可能遇到取出队列遇到锁冲突瓶颈、IO扫描浪费、CPU计算浪费的瓶颈. 以及在清除已处理订单后, 索引版本未及时清理导致的回表版本判断带来的IO浪费和CPU运算浪费瓶颈等. 本文将给出“队列处理业务的数据库性能优化”优化方法和demo演示. 性能提升10到20倍.
834 4
|
关系型数据库 分布式数据库 调度
PolarDB auto_inc 场景性能优化之路
在数据库的使用场景中, 最常见的场景是并发插入或者导入数据场景, 在该场景中并不指定自增id, 由数据库自动生成自增id, 然后插入到数据库中, 因此我们也叫auto_inc 场景的数据插入. 典型的业务场景如: 游戏行业开服过程中的大批的登录注册场景, 电商活动中给商家后台推单场景等等. 我们看看PolarDB 是如何优化针对这种并发插入场景进行优化的. 背景知识: 在这种并发
134 0
PolarDB auto_inc 场景性能优化之路
|
存储 固态存储 Cloud Native
【Paper Reading】PolarDB计算存储分离架构性能优化之路
本篇论文收录在 VLDB 2022,介绍了云原生数据库PolarDB在计算存储分离架构下遇到的性能挑战,分析了云存储相对于传统本地存储的工作特性差异及其根因,讨论了将各类存储引擎部署至云存储上时所会遇到的问题挑战,并提出了统一的优化框架 CloudJump。最后通过实验证明优化框架CloudJump适用于PolarDB,也适用于 RocksDB。
【Paper Reading】PolarDB计算存储分离架构性能优化之路
|
存储 关系型数据库 分布式数据库
Paper Reading 预告 | 揭秘 PolarDB 计算存储分离架构性能优化之路
12月29日 19:00 锁定「阿里云数据库视频号」揭秘PolarDB计算存储分离架构性能优化之路
Paper Reading 预告 | 揭秘 PolarDB 计算存储分离架构性能优化之路

热门文章

最新文章