摘要:查询重写优化既可以基于关系代数的理论进行优化,也可以基于启发式规则进行优化。

本文分享自华为云社区《openGauss内核分析(四):查询重写》,作者:酷哥。

查询重写

SQL语言是丰富多样的,非常的灵活,不同的开发人员依据经验的不同,手写的SQL语句也是各式各样,另外还可以通过工具自动生成。SQL语言是一种描述性语言,数据库的使用者只是描述了想要的结果,而不关心数据的具体获取方式,输入数据库的SQL语言很难做到是以最优形式表示的,往往隐含了一些冗余信息,这些信息可以被挖掘用来生成更加高效的SQL语句。查询重写就是把用户输入的SQL语句转换为更高效的等价SQL,查询重写遵循两个基本原则。

• 等价性:原语句和重写后的语句,输出结果相同。

• 高效性:重写后的语句,比原语句在执行时间和资源使用上更高效。

查询重写优化既可以基于关系代数的理论进行优化,例如谓词下推、子查询优化等,也可以基于启发式规则进行优化,例如Outer Join消除、表连接消除等。查询重写是基于规则的逻辑优化。

在代码层面,查询重写的架构如下:

下面以外连接消除Outer2Inner—外连接转内连接为例分析查询重写过程:在left outer join或者right outer join中,如果查询条件中存在逻辑上能够包含IS NOT NULL,例如c1 > 0,可以将查询转换成INNER JOIN,从而减少关联处理产生的中间结果集

外连接消除Outer2Inner

下面首先以一个例子来说明各种多表连接方式的区别

create table t1(c1 int, c2 int);

create table t2(c1 int, c2 int);

insert into t1 values(1, 10);

insert into t1 values(2, 20);

insert into t1 values(3, 30);

insert into t2 values(1, 100);

insert into t2 values(3, 300);

insert into t2 values(5, 500);

内连接inner join:返回两个表都满足的组合,相当于取两个表的交集

SELECT * FROM t1 inner JOIN t2 ON t1.c1 = t2.c1;

左连接 left outer join:返回左表中的所有行,如果左表中行在右表中没有匹配行,则结果中右表中的列返回空值

SELECT * FROM t1 Left OUTER JOIN t2 ON t1.c1 = t2.c1;

右连接 right outer join:返回右表中的所有行,如果右表中行在左表中没有匹配行,则结果中左表中的列返回空值

SELECT * FROM t1 right OUTER JOIN t2 ON t1.c1 = t2.c1;

全连接 full join:返回左表和右表中的所有行。当某行在另一表中没有匹配行,则另一表中的列返回空值,相当于取两个表并集

SELECT * FROM t1 full JOIN t2 ON t1.c1 = t2.c1;

在以上实验的基础上增加t2表的where条件

left join和inner join的结果是一样的,这是因为查询条件中包含WHERE t2.c2 >100这个条件,t2表所有不匹配元组均被过滤掉(包括空值),因此可以进行查询转换left-outer join -> inner join,能够有效减小t1和t2关联产生的结果集,达到性能提升的目的。

在openGauss数据库系统中,subquery_planner会遍历查询树中的rtable,看看是否有RTE_JOIN类型的节点存在,设置hasOuterJoins标志量,从而进入到reduce_outer_joins接口,满足外连接消除条件时再执行外连接的消除。 reduce_outer_Joins函数内部做两个动作,(1)reduce_outer_joins_pass1预检查,就是检查jointree中是否含有外链接,以及一些引用表的信息,为动作2做好信息采集准备,重点参考数据结构reduce_outer_joins_state;(2)reduce_outer_joins_pass2真正完成消除外链接。

void reduce_outer_joins(PlannerInfo* root)

{

reduce_outer_joins_state* state = NULL;

state = reduce_outer_joins_pass1((Node*)root->parse->jointree);

/* planner.c shouldn't have called me if no outer joins */

if (state == NULL || !state->contains_outer)

ereport(ERROR,

(errmodule(MOD_OPT),

errcode(ERRCODE_OPTIMIZER_INCONSISTENT_STATE),

(errmsg("so where are the outer joins?"))));

reduce_outer_joins_pass2((Node*)root->parse->jointree, state, root, NULL, NIL, NIL);

}

利用上一期的分析方法,可以得到查询树内存结构(查询树Query结构体中targetList存储目标属性语义分析结果,rtable存储FROM子句生成的范围表,jointree的quals字段存储WHERE子句语义分析的表达式树)

对比reduce_outer_joins运行前后查询树,jointree和rtable中的jointype都由join_left转换为join_inner,即外连接已转为内连接

(gdb) p *((JoinExpr*)(parse->jointree->fromlist->head.data->ptr_value))

$1 = {type = T_JoinExpr, jointype = JOIN_INNER, isNatural = false, larg = 0x7fdfb345cd08, rarg = 0x7fdfb345e2e8, usingClause = 0x0, quals = 0x7fdfb2f0b8a8, alias = 0x0, rtindex = 3}

(gdb) p *(RangeTblEntry*)(parse->rtable->tail.data->ptr_value)

$2 = {type = T_RangeTblEntry, rtekind = RTE_JOIN, relname = 0x0, partAttrNum = 0x0, relid = 0, partitionOid = 0, isContainPartition = false, subpartitionOid = 0, isContainSubPartition = false,

refSynOid = 0, partid_list = 0x0, relkind = 0 '\000', isResultRel = false, tablesample = 0x0, timecapsule = 0x0, ispartrel = false, ignoreResetRelid = false, subquery = 0x0, security_barrier = false,

jointype = JOIN_INNER, …}

点击关注,第一时间了解华为云新鲜技术~

openGauss内核分析:查询重写的更多相关文章

  1. openGauss内核:SQL解析过程分析

    摘要:在传统数据库中SQL引擎一般指对用户输入的SQL语句进行解析.优化的软件模块.SQL的解析过程主要分为:词法.语法和语义分析. 本文分享自华为云社区< openGauss内核分析(三):S ...

  2. SQL Server索引视图以(物化视图)及索引视图与查询重写

    本位出处:http://www.cnblogs.com/wy123/p/6041122.html 经常听Oracle的同学说起来物化视图,物化视图的作用之一就是可以实现查询重写,听起来有一种高大上的感 ...

  3. linux内核分析作业5:分析system_call中断处理过程

    1.增加 Menu 内核命令行 调试系统调用. 步骤:删除menu git clone        (tab) make rootfs 这就是我们将 fork 函数写入 Menu 系统内核后的效果, ...

  4. 《Linux内核分析》第五周 扒开系统调用的三层皮(下)

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK FIVE( ...

  5. Linux内核分析第五周学习总结:扒开系统调用的三层皮(下)

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.给MenuO ...

  6. LINUX内核分析期末总结

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.课程总结 1 ...

  7. 《Linux内核分析》实践4

    <Linux内核分析> 实践四--ELF文件格式分析 20135211李行之 一.概述 1.ELF全称Executable and Linkable Format,可执行连接格式,ELF格 ...

  8. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

  9. Linux内核分析——第五周学习笔记

    第五周 扒开系统调用的“三层皮”(下) 一.知识点总结 (一)给MenuOS增加time和time-asm命令 在实验楼中,首先 强制删除menu (rm menu -rf) 重新克隆一个新版本的me ...

  10. linux内核分析第五周学习笔记

    linux内核分析第五周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

随机推荐

  1. Java替换RequestBody和RequestParam参数的属性

    Java替换RequstBody和RequestParam参数的属性 本文主要讲解在Java环境中如何替换RequestBody和RequestParam参数中的属性 背景 近期由于接手的老项目中存在 ...

  2. JUC并发编程学习笔记(八)读写锁

    读写锁 ReadWriteLock ReadWriteLock只存在一个实现类那就是ReentrantReadWriteLock,他可以对锁实现更加细粒化的控制 读的时候可以有多个阅读器线程同时参与, ...

  3. Log4j入门使用

    前言 本篇文章主要在于,初步了解log4j,以及对它的简单使用 欢迎点赞 收藏 留言评论 私信必回哟 博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言 @ 目录 一,log4j简介 二,配 ...

  4. C/C++ 通过SQLiteSDK增删改查

    SQLite,作为一款嵌入式关系型数据库管理系统,一直以其轻量级.零配置以及跨平台等特性而备受青睐.不同于传统的数据库系统,SQLite是一个库,直接与应用程序一同编译和链接,无需单独的数据库服务器进 ...

  5. python简介和基本数据类型

    今天是2018年12月7日,开始python的学习,现在将知识点总结如下: 1  python语言有2个版本分别是 python2 .python3    区别还是很大的,例如 python2 中 1 ...

  6. Tampermonkey(油猴)的获取方法

    介绍: Tampermonkey中有大量的脚本,可以方便我们在日常的上网使用. 有那么一句话说:没有了Tampermonkey(油猴)我都不知道该如何上网. 获取Tampermonkey的步骤: 1. ...

  7. Git恢复删除的文件,一行命令就可以啦~

    情况一:删除或者修改了某个文件,但是没有add # 单个 git checkout filename # 多个 git checkout . 情况二:删除或者修改了某个文件,已经add,但是没有com ...

  8. C++ Qt开发:QItemDelegate 自定义代理组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QStyled ...

  9. 关于WPF下用户登录后再启动主窗体的实现方法

    /// <summary>App.xaml 的交互逻辑</summary> public partial class App : Application { private b ...

  10. git报错解决,warning: could not find UI helper 'git-credential-manager-ui'

    在克隆远程代码时,可能遇到这样的报错 warning: could not find UI helper 'git-credential-manager-ui' 这样的报错经常会在我们换了一台电脑或者 ...