【笔记】开发指南—SQL调优指南—SQL调优进阶—查询执行器介绍

简介: 本文介绍PolarDB-X的SQL执行器如何执行SQL中无法下推的部分。

基本概念

SQL执行器是PolarDB-X中执行逻辑层算子的组件。对于简单的点查SQL,往往可以整体下推存储层MySQL执行,因而感觉不到执行器的存在,MySQL的结果经过简单的解包封包又被回传给用户。但是对于较复杂的SQL,往往无法将SQL中的算子全部下推,这时候就需要PolarDB-X执行器执行无法下推的计算。


SELECT l_orderkey, sum(l_extendedprice *(1 - l_discount)) AS revenue
FROM CUSTOMER, ORDERS, LINEITEM
WHERE c_mktsegment = 'AUTOMOBILE'
  and c_custkey = o_custkey
  and l_orderkey = o_orderkey
  and o_orderdate < '1995-03-13'
  and l_shipdate > '1995-03-13'
GROUP BY l_orderkey;

通过EXPLAIN命令看到PolarDB-X的执行计划如下:


HashAgg(group="l_orderkey", revenue="SUM(*)")

HashJoin(condition="o_custkey = c_custkey", type="inner")
Gather(concurrent=true)
LogicalView(tables="ORDERS_[0-7],LINEITEM_[0-7]", shardCount=8, sql="SELECT `ORDERS`.`o_custkey`, `LINEITEM`.`l_orderkey`, (`LINEITEM`.`l_extendedprice` * (? - `LINEITEM`.`l_discount`)) AS `x` FROM `ORDERS` AS `ORDERS` INNER JOIN `LINEITEM` AS `LINEITEM` ON (((`ORDERS`.`o_orderkey` = `LINEITEM`.`l_orderkey`) AND (`ORDERS`.`o_orderdate` < ?)) AND (`LINEITEM`.`l_shipdate` > ?))")
Gather(concurrent=true)
LogicalView(tables="CUSTOMER_[0-7]", shardCount=8, sql="SELECT `c_custkey` FROM `CUSTOMER` AS `CUSTOMER` WHERE (`c_mktsegment` = ?)")

如下图所示,LogicalView的SQL在执行时被下发给MySQL,而不能下推的部分(除LogicalView以外的算子)由PolarDB-X执行器进行计算,得到最终用户SQL需要的结果。1.3.png

执行模型

与传统数据库采用Volcano执行模型不一样,PolarDB-X采样的是Pull~Push混合执行模型。所有算子按照计算过程中是否需要缓存临时表,将执行过程切分成多个pipeline,pipeline内部采样next()接口,按批获取数据,完成在pipeline内部的计算,pipeline间采用push接口,上游pipeline在计算完成后,会将数据源源不断推送给下游pipeline做计算。下面的例子中,被切分成两个pipeline,在pipeline-A中扫描Table-A数据,完成构建哈希表。Pipeline-B扫描Table-B的数据,然后在HashJoin算子内部做关联得到JOIN结果,再返回客户端。1.5.png

执行模式

目前 PolarDB-X 支持了三种执行模式:

  • 单机单线程(TP_LOCAL):查询过程中,是单线程计算,TP负载的查询涉及到的扫描行数比较少,往往会采用这种执行模式,比如基于主键的点查。
  • 单机并行(AP_LOCAL):查询过程中,会利用节点的多核资源做并行计算,如果您没有配置只读实例,针对AP负载的查询,往往会采样这种执行模式,一般也称之为Parallel Query模式。
  • 多机并行(MPP):您如果配置了只读实例,针对AP负载的查询,可以协调只读实例上多个节点的多核做分布式多机并行加速。

为了准确知道执行模式,在原有EXPLAIN和执行计划的基础上,扩展了EXPLAIN PHYSICAL例如以下查询,通过指令可以查看当前查询采样的是MPP模式,此外还可以获取到每个执行片段的并发数。


mysql> explain physical select a.k, count(*) cnt from sbtest1 a, sbtest1 b where a.id = b.k and a.id > 1000 group by k having cnt > 1300 or
der by cnt limit 5, 10;
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PLAN                                                                                                                                                              |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ExecutorType: MPP                                                                                                                                                 |
| The Query's MaxConcurrentParallelism: 2                                                                                                                           |
| Fragment 1                                                                                                                                                        |
|     Shuffle Output layout: [BIGINT, BIGINT] Output layout: [BIGINT, BIGINT]                                                                                       |
|     Output partitioning: SINGLE [] Parallelism: 1                                                                                                                 |
|     TopN(sort="cnt ASC", offset=?2, fetch=?3)                                                                                                                     |
|   Filter(condition="cnt > ?1")                                                                                                                                    |
|     HashAgg(group="k", cnt="COUNT()")                                                                                                                             |
|       BKAJoin(condition="k = id", type="inner")                                                                                                                   |
|         RemoteSource(sourceFragmentIds=[0], type=RecordType(INTEGER_UNSIGNED id, INTEGER_UNSIGNED k))                                                             |
|         Gather(concurrent=true)                                                                                                                                   |
|           LogicalView(tables="[000000-000003].sbtest1_[00-15]", shardCount=16, sql="SELECT `k` FROM `sbtest1` AS `sbtest1` WHERE ((`k` > ?) AND (`k` IN (...)))") |
| Fragment 0                                                                                                                                                        |
|     Shuffle Output layout: [BIGINT, BIGINT] Output layout: [BIGINT, BIGINT]                                                                                       |
|     Output partitioning: SINGLE [] Parallelism: 1 Splits: 16                                                                                                      |
|     LogicalView(tables="[000000-000003].sbtest1_[00-15]", shardCount=16, sql="SELECT `id`, `k` FROM `sbtest1` AS `sbtest1` WHERE (`id` > ?)")                     |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+

同样的也允许您通过HINT EXECUTOR_MODE指定执行模式。比如主实例空闲资源很多,可以考虑强制设置为单机或者多机并行模式来加速。


mysql> explain physical /*+TDDL:EXECUTOR_MODE=AP_LOCAL*/select a.k, count(*) cnt from sbtest1 a, sbtest1 b where a.id = b.k and a.id > 1000 group by k having cnt > 1300 order by cnt limit 5, 10;                                                                                                                                                     |

+-------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ExecutorMode: AP_LOCAL |
| Fragment 0 dependency: [] parallelism: 4 |
| BKAJoin(condition="k = id", type="inner") |
| Gather(concurrent=true) |
| LogicalView(tables="[000000-000003].sbtest1_[00-15]", shardCount=16, sql="SELECT `id`, `k` FROM `sbtest1` AS `sbtest1` WHERE (`id` > ?)") |
| Gather(concurrent=true) |
| LogicalView(tables="[000000-000003].sbtest1_[00-15]", shardCount=16, sql="SELECT `k` FROM `sbtest1` AS `sbtest1` WHERE ((`k` > ?) AND (`k` IN (...)))") |
| Fragment 1 dependency: [] parallelism: 8 |
| LocalBuffer |
| RemoteSource(sourceFragmentIds=[0], type=RecordType(INTEGER_UNSIGNED id, INTEGER_UNSIGNED k, INTEGER_UNSIGNED k0)) |
| Fragment 2 dependency: [0, 1] parallelism: 8 |
| Filter(condition="cnt > ?1") |
| HashAgg(group="k", cnt="COUNT()") |
| RemoteSource(sourceFragmentIds=[1], type=RecordType(INTEGER_UNSIGNED id, INTEGER_UNSIGNED k, INTEGER_UNSIGNED k0)) |
| Fragment 3 dependency: [0, 1] parallelism: 1 |
| LocalBuffer |
| RemoteSource(sourceFragmentIds=[2], type=RecordType(INTEGER_UNSIGNED k, BIGINT cnt)) |
| Fragment 4 dependency: [2, 3] parallelism: 1 |
| TopN(sort="cnt ASC", offset=?2, fetch=?3) |
| RemoteSource(sourceFragmentIds=[3], type=RecordType(INTEGER_UNSIGNED k, BIGINT cnt)) |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------+

在多机并行MPP执行模式的并发度是根据物理扫描行数、实例规格和计算所涉及到表的分表数来计算出来的,整体的并行度要考虑高并发场景,所以并行度的计算会偏保守,您可以通过上述EXPLAIN PHYSICAL指令查看并行度。也同样支持HINT MPP_PARALLELISM强制指定并行度。


/+TDDL:EXECUTOR_MODE=MPP MPP_PARALLELISM=8/select a.k, count(*) cnt from sbtest1 a, sbtest1 b where a.id = b.k and a
相关文章
|
机器学习/深度学习 存储 数据采集
阿里云 ACP是什么?阿里云 ACP有什么用?
ACP是什么,它是阿里云企业推出的针对于数据分析工程师的资格认证,有极高的含金量。因为阿里云在国内市场处于领先地位,他们推出的资格认证自然而然受到很多人的欢迎,很多互联网行业从业人员都以获得阿里ACP认证为荣。那么,阿里云 ACP是什么?阿里云 ACP有什么用?在认证大使官网上查阅了相关资料,我得到了答案
3079 0
阿里云 ACP是什么?阿里云 ACP有什么用?
|
存储 JSON 网络协议
阿里巴巴FastJSON使用实例
阿里巴巴FastJSON使用实例
1270 0
|
SQL 机器学习/深度学习 JSON
钉钉/企业微信机器人:“Github触发器”与“Issue机器人”
众所周知,在Serverless领域中,触发器是FaaS必不可少的一部分;一个FaaS平台,他的触发器数量、质量以及类型,很可能会决定这个FaaS平台是否能成为“主流”平台;因为触发器不仅仅是一种功能的体现,更是解决普遍性业务诉求的一个重要途径;目前来看,各个云厂商所提供的触发器基本上都会包括API网关触发器、对象存储触发器、时间触发器等,当然也有厂商提供一定的消息触发器、日志触发器、甚至是一些SQL相关的触发器、CDN触发器等,那么在我们的实际生产生活中,这些表面上看起来“很基础”的触发器,是否可以升级成为一个有趣的“高级触发器”呢?
1075 0
|
弹性计算
阿里云服务器采用AMD CPU处理器ECS实例规格大全
阿里云有AMD服务器吗?有的,阿里云百科分享阿里云服务器ECS实例采用AMD处理器的规格大全
833 0
阿里云服务器采用AMD CPU处理器ECS实例规格大全
|
存储 安全 Linux
网络安全——SSH的两种远程登录方法详解
最近在打靶场的过程中发现有时候SSH无需密码就可以直接登陆,这确实是触及到我的盲区了,上网查了一下才知道这原来是ssh的秘钥登录,花了一整天才弄懂,所以写下这篇博客,希望能帮助到大家
949 0
网络安全——SSH的两种远程登录方法详解
|
安全 前端开发 关系型数据库
PHP:ThinkPHP5.0下载安装和各种配置
PHP:ThinkPHP5.0下载安装和各种配置
1356 0
|
人工智能 安全 物联网
阿里云认证证书有含金量吗?考哪个比较好?
随着信息技术不断发展,我们的生活越来越智能化,而各大企业更是抓住了这个发展浪潮,让企业纷纷上云,这也就导致行业需要大量人才,让企业能第一眼看到你的方法就是考取阿里云认证证书,下面就和小编一起了解一下吧。
1060 0
阿里云认证证书有含金量吗?考哪个比较好?
解决报错ImportError: IProgress not found. Please update jupyter and ipywidgets.
解决方法 (1)首先很多博客说是jupyter的版本过低了,但是卸载再重装也不行:
1029 0
解决报错ImportError: IProgress not found. Please update jupyter and ipywidgets.
|
缓存 数据可视化 网络安全
可视化 DDoS 攻击地图
DDoS攻击通过分布式的源头针对在线服务发起的网络消耗或资源消耗的攻击,目的是使得目标无法正常提供服务。DDoS攻击主要针对一些重要的目标,从银行系统到新闻站点,而它之所以一直令人头疼在于如何在遭受攻击时仍然能够对用户提供正常服务。
1165 0
可视化 DDoS 攻击地图
|
存储 开发框架 前端开发
Remix 对比 Next.js :一文深度解析
在本文中,我将对比 Next.js 和 Remix 的一些重要特性,来帮助您选择最佳的React 服务端渲染框架。
2639 0