數據庫sql語句的exists總結

原文地址爲:數據庫sql語句的exists總結

數據庫sql語句的exists總結 sql exists in 學習

 

先來比較下語法:

--deals=交易表,areas=地域表,例如香港;我們的目的:查看有交易的地域

select * from areas where id in (select city_id from deals);

select * from areas where id in   (select city_id from deals where deals.city_id = areas.id);

select * from areas where exists (select null     from deals where deals.city_id = areas.id);

區別:

EXISTS語法並沒有說哪個字段落在了子查尋的結果中,而是說exists後面的語句執行的結果是不是有記錄,只要有記錄,則主查詢語句就成立。它代表‘存在’,用來引領嵌套查詢的子查詢,它不返回任何數據,只產生邏輯真值‘true’與邏輯假值‘False’。由EXISTS引出的子查詢,其目標列表達式通常都用*(用null也可以),因爲帶有EXISTS的子查詢只返回真值或假值,給出列名沒有實際意義。

 

 

性能變化的關鍵:
#1 執行的先後順序
誰是驅動表,誰先執行查詢,誰後執行查詢
#2 執行過程
exists的優點是:只要存在就返回了,這樣的話很有可能不需要掃描整個表。  
in需要掃描完整個表,並返回結果。
所以,在字表比較小的情況下,掃描全表和部分表基本沒有差別;但在大表情況下,exists就會有優勢。
看這兩個語句:
--子查詢會執行完全關聯,並返回所有符合條件的city_id

select * from areas where id in   (select city_id from deals where deals.city_id = areas.id);

--子查詢的關聯其實是一樣的,但子查詢只要查到一個結果,就返回了,所以效率還是比較高些的

 

select * from areas where exists (select null     from deals where deals.city_id = areas.id);

#3 字表查詢的結果
exists判斷子查詢的結果是不是存在,但查到什麼結果,什麼字段,並不關心;
in      需要子查詢查得的結果給主查詢使用

 

 

in 和 Exists的用法區別
1.
EXISTS 的執行流程         
select * from t1 where 
exists  ( select null from t2 where y = x )
可以理解爲 :
    for x 
in  ( select * from t1 )
    loop
       if ( 
exists  ( select null from t2 where y = x.x )
       then 
          OUTPUT THE RECORD
       end if
    end loop
對於 in exists 的性能區別 :
   
如果子查詢得出的結果集記錄較少,主查詢中的表較大且又有索引時應該用 in , 反之如果外層的主查詢記錄較少,子查詢中的表大,又有索引時使用 exists
   
其實我們區分 in exists 主要是造成了驅動順序的改變(這是性能變化的關鍵),如果是 exists ,那麼以外層表爲驅動表,先被訪問,如果是 IN ,那麼先執行子查詢,所以我們會以驅動表的快速返回爲目標,那麼就會考慮到索引及結果集的關係了
                        
另外IN時不對NULL進行處理
如:
select 1 from dual where null  
in  (0,1,2,null)
 
2.NOT  IN NOT  EXISTS :        
NOT 
EXISTS 的執行流程
select .....
   from rollup R
where not 
exists  ( select 'Found' from title T 
                              where R.source_id = T.Title_ID);
可以理解爲 :
for x 
in  ( select * from rollup ) 
       loop
           if ( not 
exists  ( that query ) ) then
                  OUTPUT
           end if;
        end;

注意:NOT EXISTS NOT IN 不能完全互相替換,看具體的需求。如果選擇的列可以爲空,則不能被替換。

例如下面語句,看他們的區別:
select x,y from t;
x               y
------          ------
1               3
3         1
1         2
1         1
3         1
5
select * from t where   x not 
in  (select y from t t2   )
no rows
        
select * from t where   not 
exists  (select null from t t2 
                                                   where t2.y=t.x )
x        y
------   ------
5        NULL
所以要具體需求來決定

對於 not  in  not  exists 的性能區別:
    not 
in 只有當子查詢中, select  關鍵字後的字段有 not null 約束或者有這種暗示時用 not  in , 另外如果主查詢中表大,子查詢中的表小但是記錄多,則應當使用 not  in , 並使用 anti hash join.
   
如果主查詢表中記錄少,子查詢表中記錄多,並有索引,可以使用 not  exists , 另外 not  in 最好也可以用 /*+ HASH_AJ */ 或者外連接 +is null
NOT 
IN 在基於成本的應用中較好

比如 :
select .....
from rollup R
where not 
exists  ( select 'Found' from title T 
                            where R.source_id = T.Title_ID);

改成(佳)

select ......
from title T, rollup R
where R.source_id = T.Title_id(+)
     and T.Title_id is null;
                                  
或者(佳)
sql> select /*+ HASH_AJ */ ...
         from rollup R
         where ource_id NOT 
IN  ( select ource_id
                                                from title T 
                                               where ource_id IS NOT NULL )

 

 

問題和解決

問題1:

 

--users表有1000條記錄,id自增,id都大於0

select * from users where exists (select * from users limit 0); --輸出多少條記錄?

select * from users where exists (select * from users where id < 0); --輸出多少條記錄?

答案(請選中查看):

10000條

0條

 原因:

exists查詢的本質,只要碰到有記錄,則返回true;所以limit根本就不會去管,或者說執行不到。

 

問題2:

exists可以完全代替in嗎?

不能。

例如:

--沒有關聯字段的情況:枚舉常量

select * from areas where id in (4, 5, 6);

--沒有關聯字段的情況:這樣exists對子查詢,要麼全true,要麼全false

select * from areas where id in (select city_id from deals where deals.name = 'xxx'); 

 

 

 

舉個相關exists的sql優化例子:

9、用exists替代in(發現好多程序員不知道這個怎麼用): 
在許多基於基礎表的查詢中,爲了滿足一個條件,往往需要對另一個表進行聯接。 
在這種情況下,使用exists(或not exists)通常將提高查詢的效率。 
舉例: 
(低效) 
select ... from table1 t1 where t1.id > 10 and pno in (select no from table2 where name like 'www%'); 
(高效) 
select ... from table1 t1 where t1.id > 10 and exists (select 1 from table2 t2 where t1.pno = t2.no and name like 'www%'); 
10、用not exists替代not in: 
在子查詢中,not in子句將執行一個內部的排序和合並。 
無論在哪種情況下,not in都是最低效的 (因爲它對子查詢中的表執行了一個全表遍歷)。 
爲了避免使用not in,我們可以把它改寫成外連接(Outer Joins)或not exists。 
11、用exists替換distinct: 
當提交一個包含一對多表信息的查詢時,避免在select子句中使用distinct. 一般可以考慮用exists替換 
舉例: 
(低效) 
select distinct d.dept_no, d.dept_name from t_dept d, t_emp e where d.dept_no = e.dept_no; 
(高效) 
select d.dept_no, d.dept_name from t_dept d where exists (select 1 from t_emp where d.dept_no = e.dept_no); 
exists使查詢更爲迅速,因爲RDBMS核心模塊將在子查詢的條件一旦滿足後,立刻返回結果. 
12、用表連接替換exists: 
通常來說,採用表連接的方式比exists更有效率。 
舉例: 
(低效) 
select ename from emp e where exists (select 1 from dept where dept_no = e.dept_no and dept_cat = 'W'); 
SELECT ENAME 
(高效) 
select ename from dept d, emp e where e.dept_no = d.dept_no and dept_cat = 'W';

 

 

R

R

R

+

R

R

R


轉載請註明本文地址:數據庫sql語句的exists總結
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章