轉自;http://tech.it168.com/a2011/0927/1252/000001252751.shtml
IT168 專稿】隨着信息化的普及,信息系統覆蓋到各行各業,根據實際業務需求,對數據庫的查詢方式越來越複雜。子查詢在複雜查詢中的使用率較高,其性能直接影響到業務處理效率,因此,優化子查詢對於DBA和開發人員是需要掌握的一項技術。如果數據庫內部可以對子查詢進行優化處理,則一方面大大減少了技術人員的工作量,另一方面也簡化了SQL語句的複雜度。DM7對子查詢進行了大量優化處理,提升了子查詢的性能。下面以DM7在相關子查詢的優化爲例進行闡述。
概述
本文中對子查詢的描述使用術語內表和外表。子查詢內出現的表稱之爲內表;只在子查詢之外出現的表稱之爲外表。
子查詢包括相關子查詢和非相關子查詢。
(1)相關子查詢
子查詢中的過濾條件存在外表列和內表列的連接,會影響最終的查詢結果。
例1:
createtable t1(c1int,c2int);
createtable t2(d1int,d2int);
select*from t1where
c1in(select d1from t2where
c2=d2);
例1中的子查詢中條件爲c2=d2,條件列分別屬於t1和t2表。查詢結果不僅要滿足c1=d1,還要滿足c2=d2。
(2)非相關子查詢
子查詢不包含外表的列,查詢結果由內表決定。
例2:
create table t1(c1int,c2int);
createtable t2(d1int,d2int);
select*from t1where
c1in(select d1from t2where
c2<10);
例2中的子查詢條件爲c2<10,最終結果需要滿足條件c1=d1 and c2<10,查詢結果不受t1表影響。
優化
1、優化前的處理方式
以外表驅動,從外表每取一條記錄,遍歷一遍內表,按照過濾條件判斷
是否滿足,如果滿足則輸出,否則不處理。相當於內表和外表做了一次笛卡爾集,在大數據量情況下,執行效率非常低。
例如,兩張60萬的數據表執行子查詢,笛卡爾集會產生3600億條記錄,對這3600億條記錄進行過濾,計算量和IO量都是巨大的,執行時間是無法被用戶接受的。
對於例1的查詢語句,執行過程如圖1所示。
▲圖1 相關子查詢優化前執行流程
2、優化後的處理方式
對於相關子查詢的優化思想是轉換爲半連接進行處理,執行過程爲:
(1) 讀取外表的一批數據;
(2) 把滿足連接條件的記錄打上標記;
(3) 處理完本批數據,返回有標記(in/exists)或無標記(not in/not exists)的記錄;
(4) 循環處理步驟1到步驟3,直到外表數據處理完。
把相關子查詢中與內表關聯的外表下放到子查詢中,與內表進行連接,連接的結果包括外表的rowid,最後以rowid爲連接條件與外表進行連接,根據規則進行優化處理,轉換爲半連接的方式,我們稱這個過程爲去相關性。
1. 非反半連接
非反半相關子查詢的算法如下:、
算法
FOR EACH row1
IN outer
table LOOP
FOR EACH row2
IN inner
table LOOP
IF jc(row1, row2)
== TRUE
&& ic(row1, row2)
== TRUE THEN
row1 can return;
END
IF;
END LOOP
END LOOP
算法中jc表示連接條件;ic表示in過濾條件。
從上述算法可以看出,只有同時滿足jc和ic的情況下,記錄纔會被輸出。因此,從算法中得出相關子查詢可以轉換爲連接查詢,連接條件爲jc and ic。下面舉例說明。
例3:
create
table t1(c1 int, c2
int);
create
table t2(d1 int, d2
int);
select c1,c2
from t1
where c1 in(select d1
from t2
where c2=d2);
對例3的去相關性優化過程分三步進行。
第一步:下放與子查詢相關的外表到子查詢中進行連接
子查詢語句轉換爲:
select t1.rowid, d1 from t2 ,t1 where c2=d2;
執行過程如圖2所示:
▲圖2 下放外表執行過程圖
第二步:子查詢與外表以t1.rowid爲條件進行半連接
原始查詢改寫爲:select c1,c2 from t1 a,(select t1.rowid, d1 from t2 ,t1 where c2=d2) b where a.rowid=b.rowid and a.c1=b.d1;
執行過程如圖3所示:
▲圖3 子查詢與外表半連接過程圖
第三步:對於滿足條件的半連接進行規則優化,條件如下:
a. 連接類型爲半連接;
b. 父親節點右孩子爲cross join,其中cross join的左孩子存在於根節點左孩子列表中,則cross join節點的左孩子替換爲根節點的左孩子,同時cross join變爲semi join。
最終的執行過程如圖4所示:
▲圖4 半連接優化過程圖