什么是提升子查询/子链接

SubLink,子查询/子链接,他们的区别:子查询不在表达式中子句,子链接在in/exists表达式中的子句。

  • 若以范围表的方式存在,则是子查询;
  • 若以表达式的存在,则是子连接;
  • 出现在FROM关键字后的子句是子查询语句,出现在where/on等约束条件或者投影中的子句是子连接

提升子链接,尝试将ANY和EXISTS子链接作为半联接或反半联接处理。

下面情况,不能实现提升。

  • 子连接右操作数:不能出现包含上层任何Var对象
  • 子连接左操作数:
    • 一定与上层出现的Var结构体表示的对象有相同,如果没有,可以直接求解,不用和上层关联
    • 不能引用上层出现的关系
    • 不能出现易失函数

提升子查询

简单子查询的提升:

select * from t01 as a, (select * from t02) as b where a.id = b.t01id and a.c1 = 100;

转化为:

select * from t01 as a, t02 as b where a.id = b.t01id and a.c1 = 100;

explain
select *
from t01 as a,
(select * from t02) as b
where a.id = b.t01id
and a.c1 = 100; QUERY PLAN
-----------------------------------------------------------------------------------
Nested Loop (cost=9.55..3118.70 rows=899 width=55)
-> Bitmap Heap Scan on t01 a (cost=4.35..32.11 rows=9 width=41)
Recheck Cond: (c1 = 100)
-> Bitmap Index Scan on idx_t01_c1 (cost=0.00..4.35 rows=9 width=0)
Index Cond: (c1 = 100)
-> Bitmap Heap Scan on t02 (cost=5.20..341.95 rows=100 width=14)
Recheck Cond: (t01id = a.id)
-> Bitmap Index Scan on idx_t02_t01id (cost=0.00..5.17 rows=100 width=0)
Index Cond: (t01id = a.id)

子查询含有集合操作、聚合操作、sort/limit/with/group, 当关键列的过滤条件使用常量,可以支持提升。

explain
select *
from t01 as a,
(select t01id, count(*) tups from t02 group by t01id) as b
where a.id = b.t01id
and a.id = 100;
QUERY PLAN
-----------------------------------------------------------------------------------
Nested Loop (cost=0.71..17.98 rows=100 width=53)
-> Index Scan using t01_pkey on t01 a (cost=0.29..8.30 rows=1 width=41)
Index Cond: (id = 100)
-> GroupAggregate (cost=0.42..7.67 rows=100 width=12)
Group Key: t02.t01id
-> Index Only Scan using idx_t02_t01id on t02 (cost=0.42..6.17 rows=100 width=4)
Index Cond: (t01id = 100)

并不是所有的子查询都能提升,含有集合操作、聚合操作、sort/limit/with/group、易失函数、from为空等,关键列的过滤条件使用非常量,是不支持提升的。 如下:

explain
select *
from t01 as a,
(select t01id, count(*) tups from t02 group by t01id) as b
where a.id = b.t01id
and a.c1 = 100;
QUERY PLAN
-----------------------------------------------------------------------------------
Hash Join (cost=20467.23..20693.85 rows=9 width=53)
Hash Cond: (t02.t01id = a.id)
-> HashAggregate (cost=20435.00..20535.16 rows=10016 width=12)
Group Key: t02.t01id
-> Seq Scan on t02 (cost=0.00..15435.00 rows=1000000 width=4)
-> Hash (cost=32.11..32.11 rows=9 width=41)
-> Bitmap Heap Scan on t01 a (cost=4.35..32.11 rows=9 width=41)
Recheck Cond: (c1 = 100)
-> Bitmap Index Scan on idx_t01_c1 (cost=0.00..4.35 rows=9 width=0)
Index Cond: (c1 = 100)

SQL改写

子查询含有集合操作、聚合操作、sort/limit/with/group、易失函数、from为空等,关键列的过滤条件使用非常量,通过SQL改写,实现提升子查询。

lateral改写

lateral关键字,可以将关联条件,写入子查询中,让子查询可以循环执行。

explain
select *
from t01 as a,
lateral (select t01id, count(*) tups, sum(b.v1) v1 from t02 as b where a.id = b.t01id group by t01id)
where a.c1 = 100;
QUERY PLAN
-----------------------------------------------------------------------------------
Nested Loop (cost=9.56..3390.67 rows=900 width=85)
-> Bitmap Heap Scan on t01 a (cost=4.35..32.11 rows=9 width=41)
Recheck Cond: (c1 = 100)
-> Bitmap Index Scan on idx_t01_c1 (cost=0.00..4.35 rows=9 width=0)
Index Cond: (c1 = 100)
-> GroupAggregate (cost=5.21..371.17 rows=100 width=44)
Group Key: b.t01id
-> Bitmap Heap Scan on t02 b (cost=5.21..369.17 rows=101 width=10)
Recheck Cond: (a.id = t01id)
-> Bitmap Index Scan on idx_t02_t01id (cost=0.00..5.18 rows=101 width=0)
Index Cond: (t01id = a.id)

any(array())改写

使用any和array将关联条件,转化为稳定函数

explain
with a as (select *
from t01 as a
where a.c1 = 100)
select *
from a,
(select t01id, count(*) tups, sum(b.v1) v1 from t02 group by t01id) as b
where a.id = b.t01id
and b.t01id = any (array (select id from a)) ;
QUERY PLAN
-----------------------------------------------------------------------------------
Hash Join (cost=2659.27..2684.79 rows=43 width=84)
Hash Cond: (t02.t01id = a.id)
CTE a
-> Bitmap Heap Scan on t01 a_1 (cost=4.35..32.11 rows=9 width=41)
Recheck Cond: (c1 = 100)
-> Bitmap Index Scan on idx_t01_c1 (cost=0.00..4.35 rows=9 width=0)
Index Cond: (c1 = 100)
InitPlan 2 (returns $1)
-> CTE Scan on a a_2 (cost=0.00..0.18 rows=9 width=4)
-> HashAggregate (cost=2626.68..2638.63 rows=956 width=44)
Group Key: t02.t01id
-> Bitmap Heap Scan on t02 (cost=52.08..2619.15 rows=1005 width=10)
Recheck Cond: (t01id = ANY ($1))
-> Bitmap Index Scan on idx_t02_t01id (cost=0.00..51.83 rows=1005 width=0)
Index Cond: (t01id = ANY ($1))
-> Hash (cost=0.18..0.18 rows=9 width=40)
-> CTE Scan on a (cost=0.00..0.18 rows=9 width=40)

子查询嵌入关联表

为了便于查询语句的共享与功能扩展,可以将关联表嵌入子查询,并使用新的子查询脚本,创建公用视图。

create view v_0102 as
select (a).*, tups
from (select a, count(*) tups,sum(v1) v1
from t02 b
join t01 a on b.t01id = a.id
group by b.t01id, a); explain
select *
from v_0102
where c1 = 100;
QUERY PLAN
-----------------------------------------------------------------------------------
Subquery Scan on t (cost=141.10..168.10 rows=900 width=48)
-> GroupAggregate (cost=141.10..159.10 rows=900 width=109)
Group Key: b.t01id, a.*
-> Sort (cost=141.10..143.35 rows=900 width=69)
Sort Key: b.t01id, a.*
-> Nested Loop (cost=4.78..96.94 rows=900 width=69)
-> Bitmap Heap Scan on t01 a (cost=4.35..32.11 rows=9 width=69)
Recheck Cond: (c1 = 1000)
-> Bitmap Index Scan on idx_t01_c1 (cost=0.00..4.35 rows=9 width=0)
Index Cond: (c1 = 1000)
-> Index Only Scan using idx_t02_t01id on t02 b (cost=0.42..6.19 rows=101 width=4)
Index Cond: (t01id = a.id)

总结

应用程序通过 SQL 语句来操作数据库时会使用大量的子查询,这种写法比直接对两个表做连接操作在结构上和思路上更清晰,尤其是在一些比较复杂的查询语句中,子查询有更完整、更独立的语义,会使 SQL 对业务逻辑的表达更清晰更容易理解,因此得到了广泛的应用。

  • 子查询 SubQuery:对应于查询解析树中的范围表,更通俗一些指的是出现在 FROM/JOIN 语句后面的独立的 SELECT 语句。
  • 子链接 SubLink:对应于查询解析树中的表达式,更通俗一些指的是出现在 where/on 子句、selectlist 里面的语句。

综上,对于查询解析树而言,SubQuery 的本质是范围表,而 SubLink 的本质是表达式。

其中分析系统和事务分析混合系统场景中,常用的 sublink 为 exist_sublink、any_sublink,在 Kingbase的优化引擎中对其应用场景做了优化(子链接提升),由于 SQL 语句中子查询的使用的灵活性,会带来 SQL 子查询过于复杂造成性能问题 。

复杂SQL子查询,通过SQL改写,可以转化为子链接,实现提升子链接。提升后的子链接,虽然可以提升在少量数据的性能,但随着数据量的增加,执行时长就会大幅度超过HASH JOIN全量数据。

KingabseES-SQL优化_提升子查询的更多相关文章

  1. paip.sql索引优化----join 代替子查询法

    paip.sql索引优化----join 代替子查询法 作者Attilax ,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.n ...

  2. 优化有标量子查询的SQL

    数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_y ...

  3. postgresql子查询优化(提升子查询)

    问题背景 在开发项目过程中,客户要求使用gbase8s数据库(基于informix),简单的分页页面响应很慢.排查发现分页sql是先查询出数据在外面套一层后再取多少条,如果去掉嵌套的一层,直接获取则很 ...

  4. 在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存)

    原文:在论坛中出现的比较难的sql问题:40(子查询 销售和历史库存) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以,觉得有 ...

  5. 在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续)

    原文:在论坛中出现的比较难的sql问题:7(子查询 判断某个字段的值是否连续) 最近,在论坛中,遇到了不少比较难的sql问题,虽然自己都能解决,但发现过几天后,就记不起来了,也忘记解决的方法了. 所以 ...

  6. 优化系列 | DELETE子查询改写优化

    0.导读 有个采用子查询的DELETE执行得非常慢,改写成SELECT后执行却很快,最后把这个子查询DELETE改写成JOIN优化过程 1.问题描述 朋友遇到一个怪事,一个用子查询的DELETE,执行 ...

  7. [慢查优化]慎用MySQL子查询,尤其是看到DEPENDENT SUBQUERY标记时

    案例梳理时间:2013-9-25 写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化,这时候还需要有一些其他基础知识的佐助, ...

  8. 分享一篇:sql语句中使用子查询,可能会引起查询的性能问题,查询时间会变长

    前段时间,做自动化适配的时候,查找需要的数据的时候,使用到了dblink,跨数据库实例进行访问,整段sql拼接再加上dblink,在plsql查询的时候,性能还不是很长时间,最多2分钟可以查到,前期调 ...

  9. Sql Server系列:子查询

    1 子查询概念 子查询是嵌套在另一个查询中的普通T-SQL查询.在有一个SELECT语句通过使用小括号创建子查询,作为另一个查询的部分数据或条件的基础. 子查询通常用于满足以下某个需求: ◊ 将一个查 ...

  10. mysql优化---in型子查询,exists子查询,from 型子查询

    in型子查询引出的陷阱:(扫更少的行,不要临时表,不要文件排序就快) 题: 在ecshop商城表中,查询6号栏目的商品, (注,6号是一个大栏目) 最直观的: mysql); 误区: 给我们的感觉是, ...

随机推荐

  1. RK3568开发笔记(三):RK3568虚拟机基础环境搭建之更新源、安装网络工具、串口调试、网络连接、文件传输、安装vscode和samba共享服务

    前言   开始搭建RK3568的基础虚拟机,具备基本的通用功能,主要包含了串口工具minicom,远程登陆ssh,远程传输filezilla,代码编辑工具vscode.   虚拟机   文档对对虚拟机 ...

  2. python中如何使两个序列相加不改变内存地址的几种方式

    # 方式1 a = [1,2,3] print(a) # 4551311680 a.extend([4,5]) print(a) # 4551311680 # 方式2 b = [1,2,3] prin ...

  3. pyqt5中通过pycharm配置designer(win和mac都适用,修改下designer目录路径即可)

    安装 pip install PyQt5 -i https://pypi.douban.com/simple pip install PyQt5-tools -i https://pypi.douba ...

  4. 2.Go 的指针

    Go的指针 1. 变量内存地址 var age = 18 // & + 变量 = 变量内存地址 fmt.Println("age:",&age) 2. 指针变量 / ...

  5. 【Azure 应用服务】当在Azure App Service的门户上 Log Stream 日志无输出,需要如何操作让其输出Application Logs呢?

    问题描述 在Azure App Service的门户上 Log Stream 日志无输出,需要如何操作让其输出Application Logs呢? 如下图所示: 问题解答 请注意,上图中提示说:App ...

  6. 【Azure Fabric Service】怎样关闭 Azure Service Fabric?

    问题描述 怎样关闭Azure Service Fabric服务呢?在Azure门户上没有找到 Stop 按钮. 问题回答 Azure Service Fabric 默认是无法停止的,可以删除. 虽然可 ...

  7. 从零开始写 Docker(三)---基于 cgroups 实现资源限制

    本文为从零开始写 Docker 系列第三篇,在mydocker run 基础上基于 cgroups 实现容器的资源限制. 完整代码见:https://github.com/lixd/mydocker ...

  8. CPack 入门指南

    背景 CPack 是 CMake 2.4.2 之后的一个内置工具,用于创建软件的二进制包和源代码包. CPack 在整个 CMake 工具链的位置. CPack 支持打包的包格式有以下种类: 7Z ( ...

  9. [学习笔记]在Linux中使用源码编译的方式安装Nginx

    ​准备工作 准备nginx源码包: http://nginx.org/en/download.html 准备相关的依赖包以及环境: gzip 模块需要 zlib 库  http://www.zlib. ...

  10. 可穿戴心电ECG监测的技术路径及特点

    在传统的医疗设备中,监测心跳速率和心脏活动是经由测量电生理讯号与心电图 (ECG) 来完成的,需要将电极连接到身体来量测心脏组织中所引发电气活动的信号.常见的设备用医院的心电图机,长期监护的动态心电仪 ...