数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换

导读

数据库的查询优化器是整个系统的"大脑",一条SQL语句执行是否高效在不同的优化决策下可能会产生几个数量级的性能差异,因此优化器也是数据库系统中最为核心的组件和竞争力之一。阿里云瑶池旗下的云原生数据库PolarDB MySQL版作为领先的云原生数据库,希望能够应对广泛用户场景、承接各类用户负载,助力企业数据业务持续在线、数据价值不断放大,因此对优化器能力的打磨是必须要做的工作之一。

本系列将从PolarDB for MySQL的查询变换能力开始,介绍我们在这个优化器方向上逐步积累的一些工作。

*本篇为「PolarDB优化器查询变换」系列第四篇,前三篇内容分别解读了:

1. Join消除

2. 窗口函数

3. Join条件下推

引言

PolarDB MySQL作为一款HTAP数据库,在复杂SQL查询优化能力上做了很多深入工作。早期用户SQL都非常简单,MySQL单机能力也有限。随着业务数据越来越多,业务场景越来越复杂,迫切需要越来越强大的数据库来满足统计、报表需求。

PolarDB在并行能力、查询变换能力、优化器等方面都做了非常深入的工作,这些工作有一个总目标:让用户的复杂查询执行得越来越快。本篇文章将对PolarDB的IN-List变换进行深入阐述,从而让我们对PolarDB的查询改写能力有更感性的认知。下面是一个常见的慢SQL:in函数运算,里面的常量比较多。

select        sum(l_extendedprice) / 7.0 as avg_yearly
fromlineitemwherel_partkey in (
9628136,19958441,10528766,.......); #in list里面有上千个常量值。

SQL语句是常见的单表过滤查询,然后进行agg汇总,实际执行耗时比较长,执行比较慢的原因是IN-List里面有上千个常量值。

原生MySQL

原生的MySQL执行计划如下:

+---------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                           |
+---------------------------------------------------------------------------------------------------+
| -> Aggregate: sum(lineitem.L_EXTENDEDPRICE)-> Filter: (lineitem.L_PARTKEY in (9628136,19958441,10528766,....) (cost=60858714.81 rows=297355930)-> Table scan on lineitem  (cost=60858714.81 rows=594711859)
|
+---------------------------------------------------------------------------------------------------+

执行过程是线性scan lineitem 5.9亿条数据,逐条去判断是不是在IN-List里面,这个算子是Item_func_in,in集合元素个数比较多,我们使用10W常量值进行测试,这个算子做求值运算耗时较长,整体完成需要 375s。

具体看下Item_func_in代码执行逻辑:

  • 判断是否可以二分查找,如可以二分查找,将IN-List转成有序数组;
  • 如果产生了有序数组,则执行时优先尝试二分查找;
  • 否则,线性scan,逐一判断左表达式是否等于IN-List里面的item。

可以看到求值逻辑已经是教优的了,这个算子基本没有优化空间了。主要是外层循环次数太多,如果能减少外层的大loop,那么就能降低延时。

PolarDB

PolarDB解决问题的思路是对该SQL做查询变换, 把IN-List转变成一张物化表,加入join list,具体变换过程如下:

Step 1:转成in子查询,上述SQL改写为

select ... from lineitem where l_partkey in (...)
====>
select ... from lineitem where l_partkey in (select dt._col_1 from (values (9628136),(19958441),...) dt)

Step 2:SubQuery Unnest-消除子查询

子查询已经是非相关的,通过SU技术,可以消除子查询,转化为semi-join。物化表经过去重,并且Join列非空,进而可以转化为inner-join。

SQL将继续改写为:

====>
select ... from lineitem, (values (9628136),(19958441),...) dt) where l_partkey = dt._col_1

通过这种变换能到得如下好处:

不用逐条去做filter,因为MySQL执行器是火山模型,增加了一个filter算子就增加了一层虚函数调用;

Join有join buffer,可以一个batch一个batch参与Join,这是转成join list的一个好处;

转成join list,join的优化非常多,如join order&access path,总能选到更优plan。

最后执行的plan如下:

+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                                                                                                 |
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Aggregate: sum(lineitem.L_EXTENDEDPRICE)-> Nested loop inner join-> Table scan on dt-> Materialize with deduplication-> scan on in-list: 100000 rows-> Index lookup on lineitem using LINEITEM_FK2 (L_PARTKEY=dt._col_1), with index condition: (lineitem.L_PARTKEY = dt._col_1)  (cost=7.34 rows=29)

物化表数据量少,作为外表,inner-join成功使用lineitem索引,只要扫10万条物化表记录,然后再使用LINEITEM_FK2索引进行连接,整条SQL执行下来只需要32s。

测试效果

PolarDB IN-List优化后在 TPCH 100G 数据集上比原生方式提升11.5倍,又因为PolarDB支持并行查询,32并行度模式下提升上百倍。

image.png

总结

原理上,PolarDB做完IN-List转换为Join-List后,能得到如下两方面的提升:

  • IN-List里面的常量都经过物化去重,基数可能会有不小的下降,这取决于重复值;
  • IN-List消去,变成了一张物化表,参与Join-List后,有更多access path选择,比如选择更好的index,更多的Join方式:hash join还是nest loop join。

细微之处见真功夫,做IN-List转换还要完成其他工作,如需要适配prepare statement协议、适配并行查询协议等,PolarDB在云数据库市场能做到特性遥遥领先,离不开背后工程师们坚持客户价值第一的初心,后续我们将介绍更多查询改写相关内容,敬请期待。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

git常用工具difftool的使用

描述 git difftool是一个 Git 命令&#xff0c;允许您使用常见差异工具在文件之间比较和编辑文件。如两版本分支间需要比较合并可以用这个工具。 命令&#xff1a; git difftool [<options>] [<commit> [<commit>]] [--] [<path>… 常见选项 -d …

【模拟IC学习笔记】 采样保持电路的设计

目录 采样保持工作原理 概念 时域响应-采保信号 采样网络的KT/C噪声 采样电容大小的选取 采样抖动(jitter) jitter对SNR的影响 法一 法二 采样开关的种类 单MOS管 实践&#xff1a;Nmos导通电阻 传输门 栅压自举开关 采样技术 上极板采样 下极板采样 采样保持…

spark的任务提交方式及流程

本地模式 local 测试用,不多赘述 分布式模式 standalone standalone集群是spark 自带的一个资源调度集群&#xff0c;分为两个角色&#xff0c;master/worker&#xff0c;master负责接收任务请求、资源调度&#xff08;监听端口7077&#xff09;&#xff0c;worker负责运行exec…

NPS 内网穿透安装

NPS 内网穿透安装 NPS 内网穿透安装服务端搭建SSH配置流程 NPS 内网穿透安装 NPS分为服务端和客户端&#xff0c;对应的不同操作系统软件可以在GitHub RELEASES自行选择下载。 服务端搭建 由于个人非企业级使用&#xff0c;为了方便直接使用docker安装 1.docker运行 (注意…

喇叭性能指标

喇叭的技术指标 灵敏度 频率响应曲线 额定阻抗 谐振频率F0 失真THD 灵敏度 灵敏度越高&#xff0c;声音越大。 f0 f0(bass resonace frequency)是最低共振频率(低频下限频),越低表示对低频的响应越好,在满足音腔空间的条件下,声音更饱满. 可直接用f0测试仪测量或通过测量阻…

DDD领域驱动设计(六)

资源库 领域对象需要资源存储。存储手段多样化,常见就是数据库,分布式缓存,localCache.资源库的作用,就是对领域的存储和访问进行统一管理对象。在抽奖平台中。通过下面这种方式组织资源库。 //数据库资源 import com.company.example.bussiness.lottery.repo.dao.AwardP…

iframe中的onload事件

动态创建的 display 为 none 的 iframe 元素&#xff0c;onload 事件不会执行 &#xff01; 昨天业务需求中碰到一个关于 iframe 不能正常跳转的棘手问题&#xff0c;一直猜测是 onload 事件引起的&#xff0c;虽然最后用 promise 暂时解决了&#xff0c;但是考虑到一些老版本的…

Qt / day01

1. 思维导图 2. 自由发挥应用场景实现一个登录窗口界面。 代码(mywidget.cpp)&#xff1a; #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {// windows setup //setup windows sizethis->resize(600, 370);//set window fixed si…

c/c++基础 自增自减运算符 大白讲解i++/i--/++i/--i

后置运算符&#xff1a;i表示在使用x之后&#xff0c;再使x的值加1&#xff0c;即ii1; 前置运算符&#xff1a;i表示在使用x之前&#xff0c;先使x的值加1&#xff0c;即ii1. 前缀运算和后缀运算的区别&#xff1a;前缀运算是“先变后用”&#xff0c;而后缀运算是“先用后变”…

app加载不到aar中的so库

如何将so文件打入到aar包中 1 在main下面新建jniLibs目录并将so放进去 2 在android{}中添加 sourceSets {main {jniLibs.srcDir file(jni/)}}app引用不到aar中的so文件(巨坑&#xff0c;不去查谁知道啊) 在aar 的manifeset application标签中中添加 android:extractNativeLi…

【idea】idea 开发快捷键

在Java开发中&#xff0c;有一些常用的快捷键和工具&#xff0c;可以提高开发效率。以下是一些常见的Java开发常用到的功能和快捷键&#xff1a; IDE快捷键&#xff1a; 格式化代码&#xff1a;Ctrl Alt L&#xff0c;会让代码更整齐&#xff0c;调整间距之类的 导入包&am…

第11课 利用windows API捕获桌面图像并通过FFmpeg分享

在上一章&#xff0c;我们已经实现了一对一音视频对话功能。在实际应用中&#xff0c;我们常需要把自己的电脑桌面分享给他人以实现桌面共享功能&#xff0c;这种功能在视频会议、在线教学等场景中很常见&#xff0c;这种功能如何实现呢&#xff1f;这节课我们就来解决这个问题…

单例模式---JAVA

目录 “饿汉”模式 完整代码 “懒汉”模式 完整代码 单例模式&#xff1a;保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例。 单例模式可以通过实例创建的时间来分为两种&#xff1a;“饿汉”和“懒汉”模式。 “饿汉”模式 所谓的“饿汉”模式实则就是在类…

用红葡萄酿造的白葡萄酒是怎样的?

“由黑变白”这是“黑葡萄”的直译&#xff0c;代表一种由深蓝到黑葡萄制成的白葡萄酒&#xff0c;这种酿酒方式起源于法国&#xff0c;黑皮诺和莫尼尔的红葡萄一直被加工成白葡萄酒&#xff0c;作为香槟的基础。这是可能的&#xff0c;因为红色浆果通常果肉较轻。红色素&#…

表分区管理

案例&#xff1a;--表分区-列表分区 --根据客户的省份分区&#xff0c;保存不通省份客户到不同的分区 CREATE table clients( id INTEGER primary key, name VARCHAR2(20), province VARCHAR2(20)) partition by list(province) ( partition shandong VALUES(山东省), …

【langchain】入门初探实战笔记(Chain, Retrieve, Memory, Agent)

1. 简介 1.1 大语言模型技术栈 大语言模型技术栈由四个主要部分组成&#xff1a; 数据预处理流程&#xff08;data preprocessing pipeline&#xff09;嵌入端点&#xff08;embeddings endpoint &#xff09;向量存储&#xff08;vector store&#xff09;LLM 终端&#xff…

*4.3 CUDA MEMORY TYPES

CUDA设备包含几种类型的内存&#xff0c;可以帮助程序员提高计算到全局内存的访问率&#xff0c;从而实现高执行速度。图4.6显示了这些CUDA设备内存。全局内存和恒定内存出现在图片的底部。主机可以通过调用API函数来写入&#xff08;W&#xff09;和读取&#xff08;R&#xf…

Hadoop集群环境下HDFS实践编程过滤出所有后缀名不为“.abc”的文件时运行报错:java.net.ConnectException: 拒绝连接;

一、问题描述 搭建完Hadoop集群后&#xff0c;在Hadoop集群环境下运行HDFS实践编程使用Eclipse开发调试HDFS Java程序&#xff08;文末有源码&#xff09;&#xff1a; 假设在目录“hdfs://localhost:9000/user/hadoop”下面有几个文件&#xff0c;分别是file1.txt、file2.tx…

Linux中RPM工具安装软件包

RPM(redhat package manager)包的命名规则(rpm 包安装的时候需要装依赖包,较为复杂 http-parser-2.8.0-2.el8.x86_64.rpm http-parser : 软件包的名称 2.8.0 : 软件包的版本号(版本号格式为主版本号.次版本号.修订号) 2 : 二进制包发布的次数,表示rpm包第2次编程生成的 el…

python+playwright 学习-1.环境准备与快速开始

前言 说到 web 自动化&#xff0c;大家最熟悉的就是 selenium 了&#xff0c;selenium 之后又出现了三个强势的框架Puppeteer、CyPress、TestCafe&#xff0c; 但这3个都需要掌握 JavaScript 语言&#xff0c;所以只是少部分人在用。 2020年微软开源一个 UI 自动化测试工具 P…