開發同事問,爲何一個標量子查詢,放在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都慢了。