当前位置: 首页 > news >正文

半连接转内连接 | OceanBase SQL 查询改写

查询优化器是关系型数据库系统的核心模块,是数据库内核开发的重点和难点,也是衡量整个数据库系统成熟度的“试金石”。为了帮助大家更好地理解 OceanBase 查询优化器,我们撰写了查询改写系列文章,带大家更好地掌握查询改写的精髓,熟悉复杂 SQL 的等价性,写出高效的 SQL。本文将重点和大家介绍半连接转内连接,更多文章欢迎进入【OceanBase SQL 查询改写专题】 查看。

引言

查询分析中经常使用子查询语句,数据库为了提高子查询的执行性能,往往会把子查询语句改写成半连接(子查询提升方法参见本系列第二篇:子查询提升首篇)。

例如,我们需要查询2022-08-01到2022-08-02之间已排片的电影,可以通过IN子查询检查电影是否在排片期内。查询SQL如Q1所示。

-- 影片表
MOVIE(movie_id primary key, movie_name, release_date)
-- 排片表
PLAY(play_id, movie_id, play_time, price, seats)Q1:
SELECT movie_name
FROM   movie
WHERE  movie_id IN (SELECT movie_idFROM   playWHERE  play_time BETWEEN DATE'2022-08-01' AND DATE'2022-08-02');Q2:
SELECT movie_name
FROM   movie LEFT SEMI
JOIN   (SELECT movie_idFROM   playWHERE  play_time BETWEEN date'2022-08-01' AND    date'2022-08-02' )play
ON     movie.movie_id = play.movie_id;

对于查询Q1,OceanBase会做子查询提升改写,改写成等价的查询Q2,使用半连接来计算子查询。对于新的查询,优化器可以选择hash left semi join、hash right semi join、merge left semi join、merge right semi join、nested loop left semi join五种连接算法执行。下图展示了其中一种执行计划。

Query Plan: 
==========================================
|ID|OPERATOR      |NAME |EST. ROWS|COST  |
------------------------------------------
|0 |HASH SEMI JOIN|     |30       |910000|
|1 | TABLE SCAN   |MOVIE|1000000  |460000|
|2 | SUBPLAN SCAN |PLAY |30       |46    |
|3 |  TABLE SCAN  |PLAY |30       |46    |
==========================================

考虑一种业务场景:movie表的数据量达100w,2022-08-01到2022-08-02之间已排片的电影约30部。上面五种连接算法都需要扫描movie表的全部数据,扫描成本比较高。而我们知道movie表的主键为movie_id,如果我们能够先查询出2022-08-01到2022-08-02之间已排片的movie_id,再去movie表查询movie_name,就能够使用movie表的主键索引,执行30次主键索引扫描即可完成查询。

为了能够按照最优计划执行Q1查询,我们需要以play表作为驱动表,并且使用index nested loop join的算法,把movie_id的连接条件转换为movie表的索引扫描条件。计划如下所示。

Query Plan: 
=====================================================
|ID|OPERATOR                   |NAME |EST. ROWS|COST|
-----------------------------------------------------
|0 |NESTED LOOP RIGHT SEMI JOIN|     |30       |91  |
|1 | SUBPLAN SCAN              |PLAY |30       |96  |
|2 |  TABLE SCAN               |PLAY |30       |96  |
|3 | TABLE GET                 |MOVIE|1        |46  |
=====================================================

但我们知道,数据库没有NESTED LOOP RIGHT SEMI JOIN的算法实现,那我们要怎样改写这条SQL,使数据库能够支持这种优化计划呢?为此,OceanBase引入了一个改写规则:半连接转内连接,将满足一定条件的半连接查询转换为内连接查询,优化器就可以针对上述场景生成最优的index nested loop join计划。

半连接转内连接

介绍半连接转内连接规则前,我们先了解下半连接的执行逻辑。还是以Q1为例进行说明,从movie表中读取一行数据,然后从play表内查找指定movie_id的数据,如果存在,则执行数据,否则不输出。从描述中我们可以知道,对于movie表中给定的一行数据,无论play表存在多少条数据与指定的movie_id相同,查询都只输出一行数据。

而内连接对于符合条件的每一条数据都会输出,也就是说,如果半连接直接转内连接,执行结果可能会重复输出多次。为了保证改写不改变查询语义,我们需要对play的movie_id去重,保证movie表的每行数据在play表中只匹配一行数据,改写后的查询如Q3所示。

Q3:
SELECT movie_name
FROM   movie INNER JOIN
JOIN   (SELECT DISTINCT movie_idFROM   playWHERE  play_time BETWEEN date'2022-08-01' AND    date'2022-08-02' )play
ON     movie.movie_id = play.movie_id;

对于新的查询Q3,优化器可以尝试movie hash join play、play hash join movie、movie merge join play、 play merge join movie、movie nested loop join play、play nested loop join movie这六种连接算法执行,比原来多了一种。此时,优化器可以生成之前描述的最优计划。

================================================
|ID|OPERATOR              |NAME |EST. ROWS|COST|
------------------------------------------------
|0 |NESTED-LOOP JOIN      |     |30       |46  |
|1 | SUBPLAN SCAN         |PLAY |30       |46  |
|2 |  MERGE DISTINCT      |     |30       |46  |
|3 |   SORT               |     |30       |46  |
|4 |    TABLE SCAN        |PLAY |30       |46  |
|5 | TABLE GET            |MOVIE|1        |7   |
================================================

注意到改写之后的查询比原来的查询多了一次去重计算,Q3查询并不是在所有场景下都比Q2查询更优,因此,OceanBase的半连接转内连接改写是一种基于代价的改写,即优化器会对比改写前后最优计划的代价,如果代价降低了,才会应用改写,否则不会改写查询。

优化点

上文我们介绍了半连接转内连接主要是增加去重计算来保证语义的正确性,也正因为增加了去重计算,改写之后的查询并不总是比改写之前的查询更优。

我们可以思考一下,是否所有场景都需要加去重计算?答案是否定的,在有些场景下,我们可以把半连接直接转成内连接,例如:play表的movie_id本身就有唯一约束,或者play表只有一行数据满足条件。在这些场景下,我们可以不添加去重计算,这也意味着改写之后的查询总是比改写之前的查询更优,不需要额外比较代价。

改写陷阱

在之前的介绍中,我们没有说明数据类型对改写规则的影响,实际上半连接转内连接对数据类型是有要求的。通过一个例子说明,对于查询Q4,如果需要改写成内连接,改写的SQL如Q5所示。

create table t1(c1 int);
insert into t1 values(0);
create table t2(c1 varchar(20));
insert into t2 values('0.0');
insert into t2 values('0.1');Q4:
SELECT *
FROM   t1
WHERE  c1 IN (SELECT c1FROM   t2); 
Q5:
SELECT t1.c1
FROM   t1INNER JOIN (SELECT DISTINCT c1FROM   t2)t2ON t1.c1 = t2.c1; 

上面的改写正确吗?对于Q4,结果是一行数据:0,对于Q5,结果是两行数据:0, 0。为什么呢?在对t2表的c1列去重时,使用的是varchar(20)类型,'0.0'与'0.1'属于不同的数据,不会发生去重操作,与t1表连接时需要把varchar(20)类型的数据转换成int类型比较,此时'0.0'与'0.1'转换成了0与0,导致执行结果不正确。

为了避免数据类型影响改写的正确性,我们需要在改写时,对数据类型做适当的处理,你可以思考一下怎样是正确的改写查询。

总结

本文主要介绍OceanBase的半连接转内连接改写,以及这个改写的优化点、容易被忽略的错误。OceanBase会把满足一定条件的半连接转换成内连接,使优化器能够尝试更多的计划,生成的查询计划可能更优。

相关文章:

半连接转内连接 | OceanBase SQL 查询改写

查询优化器是关系型数据库系统的核心模块,是数据库内核开发的重点和难点,也是衡量整个数据库系统成熟度的“试金石”。为了帮助大家更好地理解 OceanBase 查询优化器,我们撰写了查询改写系列文章,带大家更好地掌握查询改写的精髓&…...

Git使用经历

目录 1、先创建文件夹 2、仓库初始化 3、配置gitee用户名和密码 4、克隆指定仓库的中指定分支到本地仓库 5、查看当前所在分支、切换分支 6、查看状态,判断是否有修改 7、把更新的内容添加到缓存区 8、把缓存区的数据提交 9、把数据推送到远程仓库 10、把…...

永磁同步电机控制算法-自适应带宽LADRC转速控制器

一、原理介绍 设计了自适应带宽 LADRC 控制方法,继承了 LADRC 优点的同时,加入自适应带宽控制,提出运用 Softsign 函数设计带宽自适应函数,根据电机转速自动调节控制带宽,解决了永磁同步电机在复杂且多变的环境下受到…...

基于springboot+vue实现的博物馆游客预约系统 (源码+L文+ppt)4-127

摘 要 旅游行业的快速发展使得博物馆游客预约系统成为了一个必不可少的工具。基于Java的博物馆游客预约系统旨在提供高效、准确和便捷的适用博物馆游客预约服务。本文讲述了基于java语言开发,后台数据库选择MySQL进行数据的存储。该软件的主要功能是进行博物馆游客…...

LeetCode 1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解

【LetMeFly】1705.吃苹果的最大数目:贪心(优先队列) - 清晰题解 力扣题目链接:https://leetcode.cn/problems/maximum-number-of-eaten-apples/ 有一棵特殊的苹果树,一连 n 天,每天都可以长出若干个苹果。在第 i 天,…...

vim多窗格

vim打开文件分为三个阶段:buffer、window与tab buffer就是在同一个界面打开的文件window就是使用水平分割与垂直分割的窗口tab则是可以是上述两者的总集合 buffer :e filename在已打开文件的界面中再打开一个新文件,显示这个新文件,原文件被隐…...

ubuntu paddle ocr 部署bug问题解决

ubuntu paddle ocr 部署会出现异常报错。 尝试安装以下版本: pip install paddlepaddle2.5.2 -i https://pypi.tuna.tsinghua.edu.cn/simpl ​​​​​​ 助力快速掌握数据集的信息和使用方式。 数据可以如此美好!...

OpenFeign快速入门 示例:黑马商城

使用起因 之前我们利用了Nacos实现了服务的治理,利用RestTemplate实现了服务的远程调用。这样一来购物车虽然通过远程调用实现了调用商品服务的方法,但是远程调用的代码太复杂了: 解决方法 并且这种调用方式比较复杂,一会儿远程调用,一会儿本地调用。 因…...

【C++】ceil 和 floor 函数的实现与分析

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯ceil 和 floor 函数的基础介绍1. ceil 函数定义与功能示例代码输出结果功能分析使用场景 2. floor 函数定义与功能示例代码输出结果功能分析使用场景 💯自行实现…...

zabbix监控山石系列Hillstone配置模版(适用于zabbix6及以上)

监控项: 触发器: 监控数据:...

在瑞芯微RK3588平台上使用RKNN部署YOLOv8Pose模型的C++实战指南

在人工智能和计算机视觉领域,人体姿态估计是一项极具挑战性的任务,它对于理解人类行为、增强人机交互等方面具有重要意义。YOLOv8Pose作为YOLO系列中的新成员,以其高效和准确性在人体姿态估计任务中脱颖而出。本文将详细介绍如何在瑞芯微RK3588平台上,使用RKNN(Rockchip N…...

CTFHub disable_functions通关

LD_PRELOAD 来到首页发现有一句话直接就可以用蚁剑连接 根目录里有/flag但是不能看;命令也被ban了就需要绕过了 绕过工具在插件市场就可以下载 如果进不去的话 项目地址: #本地仓库;插件存放 antSword\antData\plugins 绕过选择 上传后我们点进去可以看到多了一个绕过的文件;…...

Chromium GN 目标指南 - view_example 计数器示例 (七)

1. 引言 在前面的文章中,我们学习了如何在 views_examples 中添加自定义 Button 示例。在本篇文章中,我们将继续探索 Views 框架的应用,创建一个简单的计数器示例,以学习如何使用 Label 和 Button 控件进行交互,以及如…...

一步一步写线程之十六线程的安全退出之二例程

一、说明 在一篇分析了多线程的安全退出的相关机制和方式,那么本篇就针对前一篇的相关的分析进行举例分析。因为有些方法实现的方法类似,可能就不一一重复列举了,相关的例程主要以在Linux上的运行为主。 二、实例 线程间的同步&#xff0c…...

【Linux系列】Shell 脚本中的条件判断:`[ ]`与`[[ ]]`的比较

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

ArcGIS+MIKE21 洪水淹没分析、溃坝分析,洪水淹没动态效果

洪水淹没分析过程: 一、所需数据: 1.分析区域DEM数据 二、ArcGIS软件 1.提取分析区域DEM(水库坝下区域) 2.DEM栅格转点 3.计算转换后几何点的x和y坐标值(精度20、小数位3) 4.导出属性表,形式…...

Git 的基本概念和使用

Git是一个分布式版本控制系统,它可以帮助开发人员追踪和管理代码的修改。下面是Git的基本概念和使用方式的解释: 仓库(Repository):Git使用仓库来存储代码和版本历史记录。仓库可以位于本地计算机上,也可以…...

*【每日一题 基础题】 [蓝桥杯 2024 省 B] 好数

[蓝桥杯 2024 省 B] 好数 好数 一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位……)上的数字是奇数,偶数位(十位、千位、十万位……)上的数字是偶数,我们就称之为“好数”。 给定一…...

对中文汉字排序的方法总结

写在前面 在各个系统中,都随处可见根据某个字段进行升序(ASC)或降序(DESC)进行排序展示。但进行中文汉字排序和查找的时候,对中文汉字的排序和查找结果往往都是错误的。 为了尽量提供全面的解决方法,本文会从各个层面出发告知有需要的人对应…...

【解决报错】AttributeError: ‘NoneType‘ object has no attribute ‘group‘

学习爬虫时,遇到如下报错: 报错原因: 正则表达式的 search 或 finditer 方法没有找到任何匹配项,可能是换行符处理不当等。 解决方法如下: 在正则表达式末尾加上re.S即可,re.S是一个编译标志&#xff0c…...

云容笔谈·东方红颜影像生成系统Python爬虫数据驱动创作实战

云容笔谈东方红颜影像生成系统Python爬虫数据驱动创作实战 最近在尝试用AI绘画工具“云容笔谈”来创作一些古风角色,效果确实惊艳。但有个问题一直困扰我:每次想画一个新角色,都得绞尽脑汁去想外貌、服饰、神态的描述词,效率很低…...

AI IDE 开发(公司只能用codeArts)

1,概述 AI现在这么火,我想着用AI开发一个后台管理系统试试。看看整个AI IDE开发的流程,文档检查,文档执行等。 背景:我是一个开发了5年经验的 web前端开发 程序员。不会后端,只了解基础的一些业务、数据库…...

CLAP-htsat-fused部署指南:Docker资源限制与OOM Killer规避策略

CLAP-htsat-fused部署指南:Docker资源限制与OOM Killer规避策略 1. 项目概述 CLAP-htsat-fused是一个基于LAION CLAP模型的零样本音频分类Web服务。这个工具能够对任意音频文件进行语义分类,无需预先训练特定类别的模型。无论是狗叫声、猫叫声、鸟叫声…...

离线知识问答:OpenClaw本地部署百川2-13B-4bits量化模型+私有文档库

离线知识问答:OpenClaw本地部署百川2-13B-4bits量化模型私有文档库 1. 为什么选择本地化知识问答方案 去年我在处理公司内部技术文档时遇到一个典型痛点:每次查询API规范或架构设计文档,要么需要翻找十几层文件夹,要么得在公共知…...

SEO 中的移动端优化是什么_SEO 中的长尾关键词是什么

SEO 中的移动端优化是什么 在当今互联网时代,移动设备的使用频率已经远超过了桌面电脑。无论是在日常生活中,还是在商业领域,移动端优化在SEO中的重要性愈发凸显。SEO 中的移动端优化究竟是什么呢?本文将详细解析这一问题&#x…...

汽车电子电气架构演进与关键技术解析

1. 从分布式到域控制:汽车电子电气架构的演进之路 上世纪70年代的汽车电子系统简单得令人难以置信——只有启动装置、车灯和点火系统等基础功能。我拆解过一辆1982年的老式轿车,整个电子系统仅由3个继电器和若干保险丝组成。而如今,一辆高端智…...

93.91%压缩率背后的技术革命:CompressO如何解决企业级视频处理的效率困境

93.91%压缩率背后的技术革命:CompressO如何解决企业级视频处理的效率困境 【免费下载链接】compressO Convert any video/image into a tiny size. 100% free & open-source. Available for Mac, Windows & Linux. 项目地址: https://gitcode.com/gh_mirr…...

第三章:面向对象编程

第三章:面向对象编程 【免费下载链接】wereader 一个浏览器扩展:主要用于微信读书做笔记,对常使用 Markdown 做笔记的读者比较有帮助。 项目地址: https://gitcode.com/gh_mirrors/wer/wereader 3.1 类与对象 面向对象编程的核心是类和…...

自动驾驶模仿学习避坑指南:为什么你的多模态融合模型总在十字路口“翻车”?

自动驾驶多模态融合的十字路口困境:从特征拼接走向全局理解的工程实践 当你的自动驾驶模型在封闭测试场地表现优异,却在无保护左转和行人突然穿行的复杂路口频繁"翻车"时,问题往往不在于单个传感器的精度,而在于那些看似…...

Unity发布京东小游戏反

从 UI 工程师到 AI 应用架构者 13 年前,我的工作是让按钮在 IE6 上对齐; 13 年后,我用 fetch-event-source 订阅大模型的“思维流”,用 OCR 解锁图片中的文字——前端,正在成为 AI 产品的第一道体验防线。 最近&#x…...