pg執行計劃分析小筆記

開發同事問,爲何一個標量子查詢,放在where子句後進行大小判斷,比不放在where子句後進行判斷大小運行的更快?按道理加了一次判斷,不是應該變慢麼?sql

把語句拿過來,看了一下兩個語句的執行計劃:ui

語句1和執行計劃1:blog

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。的確如開發所說。rem

如今分別來看上面的兩個執行計劃。
語句1在where子句後增長判斷,表關聯的順序是((((a,d_1),b),c),d)。語句2不在where子句後加判斷的關聯順序是(((a,b),c),d)。it

其實這裏d_1就是表示在where子句後的表e_order。這一點,能夠將語句修改一下,就能夠獲得驗證:class

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。require

回看執行計劃1,能夠看到不少關鍵字(never executed)。其實在執行計劃1中,(a,d_1)兩個表關聯後,返回的行數是0,因此以後加入鏈接的表其實並未執行實際鏈接操做,即b,c,d並未真的執行join操做。這個語句執行(a,d_1)兩個表關聯後就結束了。im

而在where子句後刪除對子查詢結果大小判斷後,表的鏈接順序是(((a,b),c),d)。從執行計劃2中能夠看到,每一個表都參與的join操做後,整個語句才執行結束。所以,時間比第一個執行計劃的時間長了。d3

這裏,子查詢結果判斷後返回的結果是0行。若是,不是0行呢?
咱們把語句1中>0.00換成=0.000000,看看執行計劃:

這個執行計劃3,就比執行計劃1和執行計劃2都慢了。

相關文章
相關標籤/搜索