數據庫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的子查詢只返回真值或假值,給出列名沒有實際意義。
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);
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