pg执行计划分析小笔记
2019-10-09 11:42 abce 阅读(2235) 评论(0) 编辑 收藏 举报开发同事问,为什么一个标量子查询,放在where子句后进行大小判断,比不放在where子句后进行判断大小运行的更快?按道理加了一次判断,不是应该变慢么?
把语句拿过来,看了一下两个语句的执行计划:
语句1和执行计划1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | SELECT A.*, /*剩余量*/ (A.q_basic - ( SELECT COALESCE ( SUM (d.q_basic), 0.00) FROM e_order d WHERE CAST (d.r_item AS INT ) = A.ID AND d.req_status NOT IN ( 'FZ' ))) AS surplus FROM e_order A LEFT JOIN e_requirement b ON A.requirement_no = b.requirement_no LEFT JOIN erp_project C ON b.factory = C.project_no WHERE 1 = 1 AND A.status IN ( 'WC' ) AND (A.q_basic - ( SELECT COALESCE ( SUM (d.q_basic), 0.00) FROM e_order d WHERE CAST (d.r_item AS INT ) = A.ID AND d.req_status NOT IN ( 'FZ' ))) > 0.00 AND (C.project_name LIKE CONCAT( '%' , 'csg18098' , '%' ) OR C.project_no LIKE CONCAT( '%' , 'csg18098' , '%' )) AND A.requirement_no LIKE CONCAT( '%' , '0000004390' , '%' ); |
语句2和执行计划2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | SELECT A.*, /*剩余量*/ (A.q_basic - ( SELECT COALESCE ( SUM (d.q_basic), 0.00) FROM e_order d WHERE CAST (d.r_item AS INT ) = A.ID AND d.req_status NOT IN ( 'FZ' ))) AS surplus FROM e_order A LEFT JOIN e_requirement b ON A.requirement_no = b.requirement_no LEFT JOIN erp_project C ON b.factory = C.project_no WHERE 1 = 1 AND A.status IN ( 'WC' ) AND (C.project_name LIKE CONCAT( '%' , 'csg18098' , '%' ) OR C.project_no LIKE CONCAT( '%' , 'csg18098' , '%' )) AND A.requirement_no LIKE CONCAT( '%' , '0000004390' , '%' ) |
从上面的执行计划看,在where之后进行大小判断后,执行时间是662.954 ms;去掉判断后执行时间是1549.644 ms。的确如开发所说。
现在分别来看上面的两个执行计划。
语句1在where子句后增加判断,表关联的顺序是((((a,d_1),b),c),d)。语句2不在where子句后加判断的关联顺序是(((a,b),c),d)。
其实这里d_1就是表示在where子句后的表e_order。这一点,可以将语句修改一下,就可以得到验证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | SELECT A.*, /*剩余量*/ (A.q_basic - ( SELECT COALESCE ( SUM (d.q_basic), 0.00) FROM e_order d WHERE CAST (d.r_item AS INT ) = A.ID AND d.req_status NOT IN ( 'FZ' ))) AS surplus FROM e_order A LEFT JOIN e_requirement b ON A.requirement_no = b.requirement_no LEFT JOIN erp_project C ON b.factory = C.project_no WHERE 1 = 1 AND A.status IN ( 'WC' ) AND (A.q_basic - ( SELECT COALESCE ( SUM (e.q_basic), 0.00) FROM e_order e WHERE CAST (e.r_item AS INT ) = A.ID AND e.req_status NOT IN ( 'FZ' ))) > 0.00 AND (C.project_name LIKE CONCAT( '%' , 'csg18098' , '%' ) OR C.project_no LIKE CONCAT( '%' , 'csg18098' , '%' )) AND A.requirement_no LIKE CONCAT( '%' , '0000004390' , '%' ); |
修改后,关联的顺序就是表关联的顺序是((((a,e),b),c),d)。故d_1就是表示在where子句后的表e_order。
回看执行计划1,可以看到很多关键字(never executed)。其实在执行计划1中,(a,d_1)两个表关联后,返回的行数是0,所以之后加入连接的表其实并未执行实际连接操作,即b,c,d并未真的执行join操作。这个语句执行(a,d_1)两个表关联后就结束了。
而在where子句后删除对子查询结果大小判断后,表的连接顺序是(((a,b),c),d)。从执行计划2中可以看到,每个表都参与的join操作后,整个语句才执行结束。因此,时间比第一个执行计划的时间长了。
这里,子查询结果判断后返回的结果是0行。如果,不是0行呢?
我们把语句1中>0.00换成=0.000000,看看执行计划:
这个执行计划3,就比执行计划1和执行计划2都慢了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
2017-10-09 SQL Server 阻止了对组件 'Agent XPs' 的 过程 'dbo.sp_set_sqlagent_properties' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。
2017-10-09 MySQL -- 异步I/O
2015-10-09 RHCE7 管理I-12归档文件并在Linux系统间复制文件
2015-10-09 RHCE7 管理II-6ACL的使用