ORACLE中NOT IN 的替代

典型的查询方式为:
SELECT TITLE
FROM BOOKSHELF
WHERE TITLE NOT IN
      (SELECT TITLE FROM BOOKSHELF_CHECKOUT)
ORDER BY TITLE;
如果BOOKSHELF_CHECKOUT很大的话,速度可能会很慢,因为ORACLE会在BOOKSHELF_CHECKOUT上执行一个时间密集型的全表扫描。

oracle 中not in 效率不高

一:
使用外部连接 
SELECT DISTINCT C.TITLE
FROM BOOKSHELF_CHECKOUT B RIGHT OUTER JOIN BOOKSHELF C
    ON B.TITLE = C.TITLE
WHERE B.TITLE IS NULL
ORDER BY C.TITLE ;
优化后的程序可以使用连接列上的索引。
WHERE B.TITLE IS NULL 
表示不出现在BOOKSHELF_CHECKOUT中的TITLE列 (ORACLE作为NULL列返回,可参考外部连接方面的内容)
二:
使用NOT EXISTS 
SELECT B.TITLE 
FROM BOOKSHELF B
WHERE NOT EXISTS
     (SELECT 'X' FROM BOOKSHELF_CHECKOUT C
      WHERE C.TITLE = B.TITLE)
ORDER BY B.TITLE
对于BOOKSHELF中每一个记录和BOOKSHELF_CHECKOUT匹配则是EXISTS.NOT EXISTS则是不存在的。 
NOT EXISTS往往可以使用可利用的索引,NOT IN 可能无法使用这些索引。

 

exists (sql 返回结果集为真) 
not exists (sql 不返回结果集为真) 
如下: 
表A 
ID NAME 
1    A1 
2    A2 
3  A3

表B 
ID AID NAME 
1    1 B1 
2    2 B2 
3    2 B3

表A和表B是1对多的关系 A.ID => B.AID

SELECT ID,NAME FROM A WHERE EXIST (SELECT * FROM B WHERE A.ID=B.AID) 
执行结果为 
1 A1 
2 A2 
原因可以按照如下分析 
SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=1) 
--->SELECT * FROM B WHERE B.AID=1有值返回真所以有数据

SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=2) 
--->SELECT * FROM B WHERE B.AID=2有值返回真所以有数据

SELECT ID,NAME FROM A WHERE EXISTS (SELECT * FROM B WHERE B.AID=3) 
--->SELECT * FROM B WHERE B.AID=3无值返回真所以没有数据

NOT EXISTS 就是反过来 
SELECT ID,NAME FROM A WHERE NOT EXIST (SELECT * FROM B WHERE A.ID=B.AID) 
执行结果为 
3 A3 
=========================================================================== 
EXISTS = IN,意思相同不过语法上有点点区别,好像使用IN效率要差点,应该是不会执行索引的原因 
SELECT ID,NAME FROM A  WHERE ID IN (SELECT AID FROM B)

NOT EXISTS = NOT IN ,意思相同不过语法上有点点区别 
SELECT ID,NAME FROM A WHERE ID NOT IN (SELECT AID FROM B)

猜你喜欢

转载自liufeng-king.iteye.com/blog/1623316