尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

SQL改写:99%DBA估计都会忽略的重大知识点

SQL改写:99%DBA估计都会忽略的重大知识点
📅 发布时间:2026/6/18 20:57:44

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面浏览效果更佳。

今天在给一个网友优化一条含有子查询的SQL时,用到了子查询转外连接的改写技术,被网友质疑改写where过滤行有问题。通过了解后,原来是网友对Where过滤行的理解有分歧导致的。这个分歧就是Where条件过滤行到底是对关联后的结果集进行过滤还是对关联前表上的行进行过滤呢?这个问题相信大部分DBA可能都会忽略的重大知识点,特别是原来在传统的Oracle纯运维的DBA尤为突出。今天就针对网友理解的这个知识点在PG环境中演示一下,通过执行计划来演示和说明一下。

1,结论

这里把结论放在前面,感兴趣的可以直接看结论,节约大家的时间。

  • 等值连接中where过滤条件是过滤表中的记录。
  • 在外连接中where过滤被关联表的列的IS NULL过滤时是对关联后的结果集进行过滤,其它是对过滤表中的记录。

2,创建测试表

这里就直接利用pg_class来创建两张测试表。

htz=# create table source as select * from pg_class;
SELECT 480
htz=# create table target as select *from pg_class;
SELECT 483

3,等值连接

3.1 模拟需求

查询source中relname为account,并且oid在target中存在的记录

htz=# explain analyze  select count(*) from source a join target b using(oid) where a.relname='account';QUERY PLAN                                                      
---------------------------------------------------------------------------------------------------------------------Aggregate  (cost=36.67..36.68 rows=1 width=8) (actual time=0.164..0.165 rows=1 loops=1)->  Hash Join  (cost=18.01..36.66 rows=1 width=0) (actual time=0.083..0.160 rows=1 loops=1)Hash Cond: (b.oid = a.oid)->  Seq Scan on target b  (cost=0.00..16.83 rows=483 width=4) (actual time=0.011..0.055 rows=483 loops=1)->  Hash  (cost=18.00..18.00 rows=1 width=4) (actual time=0.062..0.062 rows=1 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on source a  (cost=0.00..18.00 rows=1 width=4) (actual time=0.008..0.059 rows=1 loops=1)Filter: (relname = 'account'::name)Rows Removed by Filter: 479Planning Time: 0.113 msExecution Time: 0.229 ms
(11 rows)

其实上面的SQL可以等价改写为:

explain analyze  select count(*) from (select * from source where relname='account') a join target b using(oid);

执行计划如下:

htz=# explain analyze  select count(*) from (select * from source where relname='account') a join target b using(oid);QUERY PLAN                                                     
-------------------------------------------------------------------------------------------------------------------Aggregate  (cost=36.67..36.68 rows=1 width=8) (actual time=0.586..0.588 rows=1 loops=1)->  Hash Join  (cost=18.01..36.66 rows=1 width=0) (actual time=0.345..0.582 rows=1 loops=1)Hash Cond: (b.oid = source.oid)->  Seq Scan on target b  (cost=0.00..16.83 rows=483 width=4) (actual time=0.062..0.264 rows=483 loops=1)->  Hash  (cost=18.00..18.00 rows=1 width=4) (actual time=0.256..0.257 rows=1 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on source  (cost=0.00..18.00 rows=1 width=4) (actual time=0.026..0.234 rows=1 loops=1)Filter: (relname = 'account'::name)Rows Removed by Filter: 479Planning Time: 2.100 msExecution Time: 0.778 ms
(11 rows)

这里注意关键行的信息:

               ->  Seq Scan on source  (cost=0.00..18.00 rows=1 width=4) (actual time=0.026..0.234 rows=1 loops=1)Filter: (relname = 'account'::name)Rows Removed by Filter: 479

这里说明在source全表扫描,扫描完成后通过relname='account'来筛选满足条件的行,其中不满足条件的行被Filter删除了479行。

3.2 等值查询的结论

所以在等值查询中Where后面的过滤条件是直接过滤表的行。

4,外连接情况

外连接会涉及到2张表的关联,where中对2张表的过滤会带来完全不同的效果。这里我们对外连接中需要保留记录的表叫主库表,另外一张表就叫被连接表,比如在a left join b,这a就是主表,b就是被连接表;a right join b,b就是主表,a就是被连接表。where中对被驱动表中的列进行is null判断时,是对关联后的结果集进行过滤,对其它情况的过滤跟上面等值连接是一样的效果。

4.1 模拟非is null过滤需求

这里模拟一个需求就是查询target中relname为account的记录,利用oid对source进行关联,如果在source中存在,就展示source中的信息,如果不存在source返回null记录。

select * from target a  left join source b using(oid) where a.relname='account'; 

执行计划的信息如下:

htz=# explain analyze select * from target a  left join source b using(oid) where a.relname='account'; QUERY PLAN                                                    
-----------------------------------------------------------------------------------------------------------------Hash Right Join  (cost=18.05..36.66 rows=1 width=526) (actual time=0.340..0.557 rows=1 loops=1)Hash Cond: (b.oid = a.oid)->  Seq Scan on source b  (cost=0.00..16.80 rows=480 width=265) (actual time=0.015..0.179 rows=480 loops=1)->  Hash  (cost=18.04..18.04 rows=1 width=265) (actual time=0.285..0.285 rows=1 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 9kB->  Seq Scan on target a  (cost=0.00..18.04 rows=1 width=265) (actual time=0.074..0.266 rows=1 loops=1)Filter: (relname = 'account'::name)Rows Removed by Filter: 482Planning Time: 0.444 msExecution Time: 0.737 ms
(10 rows)

结果跟等值连接是一样的。

4.2 结果

结论跟等值连接一样

4.3

这里模拟一个需求就是查询target中存在oid记录,如果oid在source中不存在。

select * from target a  left join source b using(oid) where b.oid is null;

对应的执行计划如下:

htz=# explain analyze  select * from target a  left join source b using(oid) where b.oid is null;QUERY PLAN                                                      
---------------------------------------------------------------------------------------------------------------------Hash Anti Join  (cost=22.80..41.47 rows=3 width=526) (actual time=1.273..1.399 rows=3 loops=1)Hash Cond: (a.oid = b.oid)->  Seq Scan on target a  (cost=0.00..16.83 rows=483 width=265) (actual time=0.025..0.114 rows=483 loops=1)->  Hash  (cost=16.80..16.80 rows=480 width=265) (actual time=1.021..1.021 rows=480 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 102kB->  Seq Scan on source b  (cost=0.00..16.80 rows=480 width=265) (actual time=0.046..0.508 rows=480 loops=1)Planning Time: 0.305 msExecution Time: 1.650 ms

这里注意几个关键行的信息:

----------------------------------------Hash Anti Join  (cost=22.80..41.47 rows=3 width=526) (actual time=1.273..1.399 rows=3 loops=1)

优化器将SQL语句重新为反连接(not in /not exists),这个地方的where b.oid is null就是对整个结果集的过滤。上面的SQL语句其实可以重写为下面SQL:

 select * from target a where  not exists ( select * from source b where a.oid=b.oid);

改写后的执行计划如下:

htz=# explain analyze  select * from target a where  not exists ( select * from source b where a.oid=b.oid);QUERY PLAN                                                     
-------------------------------------------------------------------------------------------------------------------Hash Anti Join  (cost=22.80..41.47 rows=3 width=265) (actual time=0.111..0.132 rows=3 loops=1)Hash Cond: (a.oid = b.oid)->  Seq Scan on target a  (cost=0.00..16.83 rows=483 width=265) (actual time=0.007..0.032 rows=483 loops=1)->  Hash  (cost=16.80..16.80 rows=480 width=4) (actual time=0.064..0.065 rows=480 loops=1)Buckets: 1024  Batches: 1  Memory Usage: 25kB->  Seq Scan on source b  (cost=0.00..16.80 rows=480 width=4) (actual time=0.003..0.037 rows=480 loops=1)Planning Time: 0.126 msExecution Time: 0.221 ms
(8 rows)

4.4 结论

在外连接中对被连接列进行IS NULL过滤时是对关联后的结果集进行判断和过滤。

4 总结论

关于整个实验的结论,可以参考第一部分,这里简单写一下关于怎么快速的进行上面判断,只需要看执行计划是否存在表上面有Filter过滤即可。

------------------作者介绍-----------------------
姓名:黄廷忠
个人博客: (http://www.htz.pw)
CSDN地址: (https://blog.csdn.net/wwwhtzpw)
博客园地址: (https://www.cnblogs.com/www-htz-pw)

提供ORACLE技术支持(系统优化,故障处理,安装升级,数据恢复等) TEL:18081072613,微信、QQ同手机号。

相关新闻

  • 2025年办公室玻璃隔断型材厂家权威推荐榜单:专业玻璃隔断/广州办公室隔断/双层玻璃百叶隔断源头厂家精选
  • 【运维自动化-标准运维】各类全局变量使用说明-元变量(完结)
  • 2025年不变色二氧化硅厂家权威推荐榜单:通用型二氧化硅/可定制二氧化硅/高吸油二氧化硅源头厂家精选

最新新闻

  • 2026南阳黄金回收白银回收铂金回收门店实测|本地正规实体老店无套路门店推荐 - 中安检金银铂钻回收
  • 2026厦门黄金回收白银回收铂金回收门店实测|本地正规实体老店无套路门店推荐 - 中安检金银铂钻回收
  • 2026荆州黄金回收白银回收铂金回收门店实测|本地正规实体老店无套路门店推荐 - 中安检金银铂钻回收
  • AAFF论坛精粹|光影与新生:赵非、卞灼跨越代际的影像哲思
  • lsyat门禁闸机获取历史记录—幽冥大陆(一百38)-东方仙盟
  • Kafka07-集成-尚硅谷

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号