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

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. ubuntu16.04 ssh启用root连接

    安装好ubuntu16.04 server版默认是不允许客户端ssh工具连接root的. 启用方法如下: 1.设置root密码 dylan@ubuntu:~$ sudo passwd root [su ...

  2. 我的小程序之旅六:微信公众号授权登录(适用于H5小程序)

    实现步骤 1 第一步:用户同意授权,获取code 2 第二步:通过code换取网页授权access_token 3 第三步:刷新access_token(如果需要) 4 第四步:拉取用户信息(需sco ...

  3. String--cannot convert from 'const char *' to 'LPTSTR'错误

    这种错误,很多情况下是类型不匹配 LPTSTR表示为指向常量TCHAR字符串的长指针 TCHAR可以是wchar_t或char,基于项目是多字节还是宽字节版本. 看下面的代码,代码来源:Example ...

  4. Kotlin 协程五 —— 在Android 中使用 Kotlin 协程

    目录 一.Android MVVM 结构 二.添加依赖 三.在后台线程中执行 3.1 协程解决了什么问题 3.2 保证主线程安全 3.3 withContext 的性能 四.结构化并发 4.1 追踪协 ...

  5. java数组实现的超市管理系统(控制台)

    说明:使用数组存储数据,针对用户功能1:增加用户2:删除用户3:修改用户:针对商品功能:1.显示所有商品2.修改商品信息3.添加商品信息4.删除商品信息5.查询商品信息 效果展示 ========== ...

  6. Java 线程通信的应用:经典例题:生产者/消费者问题

    1 package bytezero.threadcommunication; 2 3 /** 4 * 线程通信的应用:经典例题:生产者/消费者问题 5 * 6 * 7 * 8 * @author B ...

  7. Visual Studio部署C++环境下OpenCV库

      本文介绍在Visual Studio 2022中配置.编译C++计算机视觉库OpenCV的方法. 1 OpenCV库配置   首先,我们进行OpenCV库的下载与安装.作为一个开源的库,我们直接在 ...

  8. nginx判断是否手机访问

    if ( $http_user_agent ~* "(Android|iPhone|Windows Phone|UC|Kindle|MicroMessenger |iPad)" ) ...

  9. Python面向对象之面向对象编程

    [一]什么是面向过程 [1]面向过程介绍 面向过程,核心在于 "过程" 二字 过程的终极奥义就是将程序 "流程化" 过程是 "流水线" ,用 ...

  10. jQuery 框架

    jQuery 框架 目录 jQuery 框架 一. 概述 二. jQuery 安装引用 2.1 安装 2.2 本地导入使用 2.3 jQuery CDN引入 三. jQuery基本语法 四. 查找标签 ...