分享一次公司晋级考试的SQL题目,非常有趣的案例(postgresql 标量子查询 where lie 谓词过滤条件)
同事今天晋级高级工程师考试,发来一道公司出题目让我帮忙进行优化,其中场景二的案例非常有意思。
题目内容如下:
原始SQL:
scott=> explain analyze
scott-> select
scott-> a.id,
scott-> a.col2,
scott-> (select sum(b.id) from table02 b where a.col2 like b.col2||'%' )
scott-> from table01 a; QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Seq Scan on table01 a (cost=0.00..3905341.00 rows=100000 width=45) (actual time=0.579..50568.090 rows=100000 loops=1)
SubPlan 1
-> Aggregate (cost=39.02..39.03 rows=1 width=8) (actual time=0.504..0.504 rows=1 loops=100000)
-> Seq Scan on table02 b (cost=0.00..39.00 rows=10 width=4) (actual time=0.063..0.499 rows=8 loops=100000)
Filter: (a.col2 ~~ (col2 || '%'::text))
Rows Removed by Filter: 1992
Planning Time: 0.097 ms
Execution Time: 50590.882 ms
(8 行记录) 时间:50591.756 ms (00:50.592)
table01、table02 这两张表没有创建任何索引,全表扫描+标量子查询SQL执行需要50s才能出结果,速度非常慢。
考题要求要优化这条SQL,意思既是无论是调整 postgresql数据库的参数,对SQL加索引,等价改写SQL,这些手段都没问题,只要能让执行速度变快就行。
由于当时我在忙其他的事情,大致看了一眼后给出了以下的改写方案(我没加索引,感觉加索引的用处不大):
改写1:
scott=> explain analyze select
scott-> a.id,
scott-> a.col2,
scott-> b.sum_b_id
scott-> from table01 a
scott-> left join (select sum(b.id) sum_b_id,b.col2 from table02 b group by b.col2) b
scott-> ON a.col2 like b.col2||'%'
scott-> ; QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
Nested Loop Left Join (cost=39.00..448135.74 rows=127500 width=45) (actual time=1.283..8674.517 rows=100000 loops=1)
Join Filter: (a.col2 ~~ (b.col2 || '%'::text))
Rows Removed by Join Filter: 25400387
-> Seq Scan on table01 a (cost=0.00..1841.00 rows=100000 width=37) (actual time=0.018..19.620 rows=100000 loops=1)
-> Materialize (cost=39.00..45.37 rows=255 width=11) (actual time=0.000..0.024 rows=255 loops=100000)
-> HashAggregate (cost=39.00..41.55 rows=255 width=11) (actual time=1.241..1.316 rows=255 loops=1)
Group Key: b.col2
-> Seq Scan on table02 b (cost=0.00..29.00 rows=2000 width=7) (actual time=0.007..0.342 rows=2000 loops=1)
Planning Time: 0.181 ms
Execution Time: 8682.974 ms
(10 行记录) 时间:8684.338 ms (00:08.684)
可以看到等价改写以后,SQL从原来执行 50s 的时间已经降低到 8.8s 左右,提升还是挺大的。
把答案给了同事,我也去忙其他的事情了。
晚上我闲下来没事做,贼无聊,仔细看了下改写1 SQL的执行计划,感觉这种计划可能不是最优的执行计划。
因为我始终感觉走HASH可能才是最佳的执行计划,如果这条SQL在ORACLE 上执行,CBO很大可能会让计划走HASH,但是在PG就是走NL(脑残优化器)。
吃完饭后一直在尝试改写,搞了哥很长时间,最终还是把HASH版本的SQL给改出来了,泪目。
改写2:
scott=> explain analyze
scott-> with a as (select id,col2,substr(t1.col2,1,x.rn) rn1 from table01 t1,
scott(> scott(> (select min(length(col2)) rn from table02) x),
<t2.col2,1,x.rn) rn2 from (select sum(b.id) sum_b_id,b.col2 from table02 b group by b.col2) t2,
scott(> (select min(length(col2)) rn from table02) x)
scott-> select a.id,a.col2,b.sum_b_id from a
scott-> left join b on a.rn1 = b.rn2 and a.col2 like b.col2||'%';
QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------
--------
Hash Left Join (cost=127.86..14881.38 rows=100000 width=45) (actual time=2.322..215.695 rows=100000 loops=1)
Hash Cond: (substr(t1.col2, 1, (min(length(table02.col2)))) = substr(b.col2, 1, (min(length(table02_1.col2)))))
Join Filter: (t1.col2 ~~ (b.col2 || '%'::text))
-> Nested Loop (cost=39.00..2880.02 rows=100000 width=41) (actual time=0.588..36.635 rows=100000 loops=1)
-> Aggregate (cost=39.00..39.01 rows=1 width=4) (actual time=0.580..0.582 rows=1 loops=1)
-> Seq Scan on table02 (cost=0.00..29.00 rows=2000 width=3) (actual time=0.015..0.252 rows=2000 loops=1)
-> Seq Scan on table01 t1 (cost=0.00..1841.00 rows=100000 width=37) (actual time=0.005..15.073 rows=100000 loops=1)
-> Hash (cost=85.67..85.67 rows=255 width=15) (actual time=1.721..1.724 rows=255 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 20kB
-> Nested Loop (cost=78.00..85.67 rows=255 width=15) (actual time=1.500..1.602 rows=255 loops=1)
-> Aggregate (cost=39.00..39.01 rows=1 width=4) (actual time=0.554..0.555 rows=1 loops=1)
-> Seq Scan on table02 table02_1 (cost=0.00..29.00 rows=2000 width=3) (actual time=0.004..0.233 rows=2000 l
oops=1)
-> HashAggregate (cost=39.00..41.55 rows=255 width=11) (actual time=0.945..1.002 rows=255 loops=1)
Group Key: b.col2
-> Seq Scan on table02 b (cost=0.00..29.00 rows=2000 width=7) (actual time=0.005..0.250 rows=2000 loops=1)
Planning Time: 0.351 ms
Execution Time: 224.017 ms
(17 行记录) 时间:225.488 ms
这个案例从最早的 50秒 改写到 8秒,到最后的 225毫秒出结果,花了不少时间研究各种改写方式。
只能说PG的优化器确实太拉跨了,浪费开发者不少时间,换成ORACLE数据库不会走这种SB执行计划。
以后估计会很少发博客,目前正在考虑转行卖炒粉,目前市场真的是一言难尽。
分享一次公司晋级考试的SQL题目,非常有趣的案例(postgresql 标量子查询 where lie 谓词过滤条件)的更多相关文章
- SQL Server的优化器会缓存标量子查询结果集吗
在这篇博客"ORACLE当中自定义函数性优化浅析"中,我们介绍了通过标量子查询缓存来优化函数性能: 标量子查询缓存(scalar subquery caching)会通过缓存结果减 ...
- 反连接NOT EXISTS子查询中有or 谓词连接条件SQL优化一例
背景 今天在日常数据库检查中,发现一SQL运行时间特别长,于是抓取出来,进行优化. 优化前: 耗时:503s 返回:0 SQL代码 SELECT * FROM MM_PAYABLEMONEY_TD P ...
- SQL Server调优系列基础篇(子查询运算总结)
前言 前面我们的几篇文章介绍了一系列关于运算符的介绍,以及各个运算符的优化方式和技巧.其中涵盖:查看执行计划的方式.几种数据集常用的连接方式.联合运算符方式.并行运算符等一系列的我们常见的运算符.有兴 ...
- 优化有标量子查询的SQL
数据库环境:SQL SERVER 2008R2 今天在数据库中抓出一条比较耗费资源的SQL,只返回904条数据,居然跑了40多分钟.SQL及对应的数据量如下图: SELECT saft04.cur_y ...
- 标量子查询SQL改写
一网友说下面sql跑的好慢,让我看看 sql代码: select er, cid, pid, tbl, zs, sy, (select count(sr.mobile_tele_no) from tb ...
- SQL优化-标量子查询(数据仓库设计的隐患-标量子查询)
项目数据库集群出现了大规模节点宕机问题.经查询,问题在于几张表被锁.主要问题在于近期得几个项目在数据库SQL编写时大量使用了标量子查询. 为确定为题确实是由于数据表访问量超过单节点限制,做了一些测试. ...
- 标量子查询调优SQL
fxnjbmhkk4pp4 select /*+ leading (wb,sb,qw) */ 'blocker('||wb.holding_session||':'||sb.username||')- ...
- 在 SQL Server 数据库的 WHERE 语句中使用子查询
这是关于子查询语句的一系列文章中的第三篇.在这篇文章中我们将讨论WHERE语句中的子查询语句.其他的文章讨论了其他语句中的子查询语句. 本次课程中的所有例子都是基于Microsoft SQL Serv ...
- 数据库开发基础-SQl Server 主键、外键、子查询(嵌套查询)
主键 数据库主键是指表中一个列或列的组合,其值能唯一地标识表中的每一行.这样的一列或多列称为表的主键,通过它可强制表的实体完整性.当创建或更改表时可通过定义 PRIMARY KEY约束来创建主键.一个 ...
- SQL 必知必会·笔记<9>使用子查询
子查询(subquery),即嵌套在其他查询中的查询. 1. 利用子查询进行过滤 SELECT 语句中,子查询总是从内向外处理.示例: SELECT cust_name, cust_contact F ...
随机推荐
- msvc++工程之vs版本升级及工程目录规范
为什么要升级msvc++工程版本 对msvc++工程进行vs版本升级,一方面是可以使用较新的C++标准及对64位更好的支持. 首先你需要对msvc++ project文件有一定的了解,主要是vcxpr ...
- croc-文件传输工具
前言 croc是一款用go语言开发的命令行文件传输工具,该工具允许两台计算机设备以一种简单和安全的方式来传输文件. GitHub项目地址 环境信息 IP 系统版本 croc版本 说明 192.168. ...
- [clickhouse]同步MySQL
前言 clickhouse的查询速度非常快,而且兼容大部分MySQL的sql语法,因此一般将clickhouse作为MySQL的读库. 本文提供两种clickhouse同步MySQL的方式 click ...
- 微信的 h5 支付和 jsapi 支付
目录 申请商户号 申请商户证书 设置APIv3密钥 下载 SDK 开发包 下载平台证书 关联 AppID 账号 开通 H5 支付 H5支付流程 开通 JSAPI 支付 JSAPI 支付流程 通用微信支 ...
- IDA函数特征识别自动签名
IDA函数特征识别自动签名 Vc6编译的有些无法识别一些库里面的函数 测试代码 #include <stdio.h> int main() { printf("123456\n& ...
- Hugging News #0821: 新的里程碑:一百万个代码仓库!
每一周,我们的同事都会向社区的成员们发布一些关于 Hugging Face 相关的更新,包括我们的产品和平台更新.社区活动.学习资源和内容更新.开源库和模型更新等,我们将其称之为「Hugging Ne ...
- Solution -「CCPC Winter Camp Day 6 A」Convolution
Description Link. 给定一个数列 \(\sf a_1,a_2,....a_n\),请求出下面这个结果在模 \(\sf 998244353\) 下的答案. \[\sum_{i=1}^{n ...
- CAP项目集成带身份和证书验证的MongoDB
大家好,我是Edison. 最近,在使用CAP事件总线时,碰到了这样一个需求:微服务采用的是MongoDB,而且还是带身份验证 和 SSL根证书验证的.由于目前网上能找到的资料,都是不带身份验证的Mo ...
- .NET开发工作效率提升利器 - CodeGeeX AI编程助手
前言 2022年6月,随着GitHub Copliot正式面向大众发布.让许多开发者都感受到了AI辅助编程工具的魅力所在,Copilot实现了帮助开发者大大提高了编程开发效率,让程序员朝九晚五成为可能 ...
- 基本环境安装 jdk,mq,redis,nginx
JDK:解压安装包,命令为 tar -zxvf jdk-8u381-linux-x64.tar.gz配置环境变量,使用 vim 命令(需要安装vim,安装命令为:yum install vim)修改 ...