1. 程式人生 > >使用 EXISTS 代替 IN 和 inner join

使用 EXISTS 代替 IN 和 inner join

在使用Exists時,如果能正確使用,有時會提高查詢速度:

      1,使用Exists代替inner join

      2,使用Exists代替 in

  1,使用Exists代替inner join例子:

     在一般寫sql語句時通常會遇到如下語句:

      兩個表連線時,取一個表的資料,一般的寫法通過關聯查詢(inner join):      

select a.id, a.workflowid,a.operator,a.stepid from  dbo.[[zping.com]]] a inner join workflowbase b on a.workflowid=b.id and operator='4028814111ad9dc10111afc134f10041'

 查詢結果:

(1327 行受影響) 表 'Worktable'。掃描計數 0,邏輯讀取 0 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 'workflowbase'。掃描計數 1,邏輯讀取 293 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 '[zping.com]'。掃描計數 1,邏輯讀取 1339 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

   還有一種寫法使用exists來取資料

select a.id,a.workflowid,a.operator ,a.stepid from  dbo.[[zping.com]]] a where exists (select 'X' from workflowbase b where a.workflowid=b.id) and operator='4028814111ad9dc10111afc134f10041'

 執行結果:  

(1327 行受影響) 表 '[zping.com]'。掃描計數 1,邏輯讀取 1339 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 'workflowbase'。掃描計數 1,邏輯讀取 291 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

   這裡兩著的IO次數,EXISTS比inner join少 2個IO, 對比執行計劃成本不一樣, 看看兩著的差異:  

 

   這時我們發現使用EXISTS要比inner join效率稍微高一下。        2,使用Exists代替 in

      要求:編寫workflowbase表中id不在表中dbo.[[zping.com]]]的行:      

       一般的寫法:

select * from workflowbase   where  id not in ( select  a.workflowid from  dbo.[[zping.com]]] a )

執行結果:

複製程式碼

(1 行受影響) 表 'Worktable'。掃描計數 0,邏輯讀取 0 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 '[zping.com]'。掃描計數 5,邏輯讀取 56952 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 'workflowbase'。掃描計數 3,邏輯讀取 1589 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 'Worktable'。掃描計數 0,邏輯讀取 0 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

複製程式碼

    使用Existsl來寫:

select * from workflowbase b  where not exists( select 'X' from  dbo.[[zping.com]]] a where a.workflowid=b.id )

   看看執行結果

(1 行受影響) 表 'Worktable'。掃描計數 0,邏輯讀取 0 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 '[zping.com]'。掃描計數 3,邏輯讀取 18984 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 表 'workflowbase'。掃描計數 3,邏輯讀取 1589 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

  兩個io的差距:56952+1589=58541次 (使用IN)

                     18984+1589=20573次  (使用Exists)

   使用exists是in的2.8倍,查詢效能提高很大。

    EXISTS 使查詢更為迅速,因為RDBMS核心模組將在子查詢的條件一旦滿足後,立刻返回結果。

in和inner join在大多數情況下都是返回兩表的交集,但是兩者還是有區別的,如下例子

mysql> select * from a; +------+------+ | id   | name | +------+------+ |    1 | a    | |    2 | b    | |    3 | c    | +------+------+

MySQL> select * from b; +------+------+ | id   | name | +------+------+ |    1 | d    | |    1 | g    | |    2 | e    | |    4 | f    | +------+------+

mysql> select a.id, a.name from a where a.id in (select b.id from b); +------+------+ | id   | name | +------+------+ |    1 | a    | |    2 | b    | +------+------+

mysql> select a.id, a.name from a inner join b on (a.id = b.id); +------+------+ | id   | name | +------+------+ |    1 | a    | |    1 | a    | |    2 | b    | +------+------+

mysql> select * from a inner join b on (a.id = b.id); +------+------+------+------+ | id   | name | id   | name | +------+------+------+------+ |    1 | a    |    1 | d    | |    1 | a    |    1 | g    | |    2 | b    |    2 | e    | +------+------+------+------+

從查詢結果中可以看出,in的結果是不會有重複的,對非主鍵進行join時,join的結果是有重複的。如果說還有另一個區別的話就是join會產生一個兩表合併的臨時表,in不會產生兩表合併的臨時表。