使用 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不會產生兩表合並的臨時表。



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM