SQL里面嵌套子查詢這是非常普遍的寫法。
下面是有關子查詢的一些說明:
子查詢又稱內部查詢,而包含子查詢的語句稱之外部查詢(又稱主查詢)。
所有的子查詢可以分為兩類,即相關子查詢和非相關子查詢。
非相關子查詢是獨立於外部查詢的子查詢,子查詢總共執行一次,執行完畢后將值傳遞給外部查詢。
相關子查詢的執行依賴於外部查詢的數據,外部查詢執行一行,子查詢就執行一次。
這個解釋沒問題,但是上周碰到個問題,2層子查詢,其中相關子查詢作為內層子查詢,外層的是非相關的。這樣的子查詢到底算相關還是非相關呢?
select a.pro_name, a.pro_type, a.pro_price
from supmka a, supmkb_1 b
where a.pro_name = b.pro_name
and a.pro_type = b.pro_type
and a.pro_price =
(select
d.pro_price
from(
select
distinct
c.pro_price
from supmkb_2 c
where c.pro_no = b.pro_no)
d
where rownum = 1);
紅色標注的子查詢是相關的(內層的表c和主查詢的表b關聯),而外層藍色的是非相關的。
查看執行計划之后,發現優化器先做的紅色部分的查詢,然后再做藍色,再做關聯。也就是說,紅色部分的
c.pro_no = b.pro_no,優化器忽略了(版本是Oracle Database
10g Enterprise Edition Release
10.2.0.1.0)
這樣的數據查出來肯定有問題。
如果把distinct的位置換一下,
select a.pro_name, a.pro_type, a.pro_price
from supmka a, supmkb_1 b
where a.pro_name = b.pro_name
and a.pro_type = b.pro_type
and a.pro_price =
(select
distinct
d.pro_price
from (
select
c.pro_price
from supmkb_2 c
where c.pro_no = b.pro_no)
d
where rownum = 1);
優化器會先做關聯查詢。把
c.pro_no = b.pro_no
條件帶進去做查詢了。
所以大家不要寫這種關聯嵌套非關聯的子查詢,優化器都不知道怎么處理了。
另外在做實驗期間,還發現一個問題:
在Oracle Database 10g Enterprise Edition Release
10.2.0.3.0
上執行
select a.pro_name, a.pro_type, a.pro_price
from supmka a, supmkb_1 b
where a.pro_name = b.pro_name
and a.pro_type = b.pro_type
and a.pro_price =
(select
d.pro_price
from (
select
distinct
c.pro_price
from supmkb_2 c
where c.pro_no = b.pro_no)
d
where rownum = 1);
會報ora-00904,b.pro_no字段沒有定義的錯誤。也就是說,優化器還是先執行了紅色部分的SQL,但是並沒有把where c.pro_no = b.pro_no條件忽略,導致了00904的錯誤。
而在
10.2.0.1.0
版本上,優化器直接忽略了where c.pro_no = b.pro_no條件。
實際上這個SQL寫得非常不好。zizi只是抱着一種蛋疼的精神分析了一下SQL執行順序,也算打發無聊的時間吧