首页 > 其他 > 详细

pg执行计划分析小笔记

时间:2019-10-09 12:30:27      阅读:146      评论:0      收藏:0      [点我收藏+]

开发同事问,为什么一个标量子查询,放在where子句后进行大小判断,比不放在where子句后进行判断大小运行的更快?按道理加了一次判断,不是应该变慢么?

把语句拿过来,看了一下两个语句的执行计划:

语句1和执行计划1:

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:

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。这一点,可以将语句修改一下,就可以得到验证:

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都慢了。

pg执行计划分析小笔记

原文:https://www.cnblogs.com/abclife/p/11640799.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!