驅動表普遍認為是由SQL語句的寫法決定的,簡單的說,就是FROM語句后面的表列表中的最后一個。由於SQL語句是從后向前進行分析,Oracle會根據FROM語句從后到前將各個表依次連接起來。
首先理解執行順序
先從最開頭一直往右看,直到看到最右邊的並列的地方,對於不並列的,靠右的先執行:對於並列的,靠上的先執行。
即並列的縮進,從上往下執行,非並列的縮進塊,從下往上執行。1. 如果所連接的表A和B,A表長度遠遠大於B表,建議從較大的A表上驅動。(簡言之 大值為驅動表)
2. 如果Where子句中含有選擇性條件,Where No=20,將最具有選擇性部分放在表達式最后。
3. 如果只有一個表有索引,另一表無索引,無索引的表通常作為驅動表。
如A表的No列以被索引,而B表的No列沒被索引,
則應當B表作為驅動表,A表作為被驅動表。
RBO或者CBO沒有分析table的情況下,對於2個表的操作,FROM子句中,RBO選擇最右的表作為驅動表(一般也就是from 中最后的表作為驅動表 )。
所以 對於NESTED LOOPS、HASH JOIN、SORT MERGE JOIN方式,驅動表選擇較小的表 (放在from 最右端),速度會更快;
存在主、外鍵關系的表,由於主鍵由oracle自動建立索引,外鍵上最好也建索引,以避免全表掃描 。
而對於3個或以上table連接查詢,對於FROM子句,RBO以從右到左的順序處理表連接,也就是from 子句最右端table作為驅動表。
SQL>CREATE TABLE T1 AS SELECT * FROM USER_TABLES;
表已創建。
SQL>CREATE TABLE T2 AS SELECT * FROM USER_INDEXES;
表已創建。
SQL>SET AUTOT ON EXP
SQL> SELECT COUNT(*) FROM T1, T2 WHERE T1.TABLE_NAME = T2.TABLE_NAME;COUNT(*)
----------
37Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 MERGE JOIN
3 2 SORT (JOIN)
4 3 TABLE ACCESS (FULL) OF 'T2'
5 2 SORT (JOIN)
6 5 TABLE ACCESS (FULL) OF 'T1'
T2 是驅動表
SQL> SELECT COUNT(*) FROM T2, T1 WHERE T1.TABLE_NAME = T2.TABLE_NAME;
COUNT(*)
----------
37Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 MERGE JOIN
3 2 SORT (JOIN)
4 3 TABLE ACCESS (FULL) OF 'T1'
5 2 SORT (JOIN)
6 5 TABLE ACCESS (FULL) OF 'T2'
根據這個例子,可以看出,SQL語句的寫法對於驅動表的影響。
然而,實際上驅動表和連接順序的選擇要比上面的觀點復雜的多,下面對稍微調整一下這個例子。
T1 是驅動表
SQL> ALTER TABLE T1 ADD CONSTRAINT PK_T1 PRIMARY KEY (TABLE_NAME);
表已更改。
SQL> SELECT COUNT(*) FROM T1, T2 WHERE T1.TABLE_NAME = T2.TABLE_NAME;
COUNT(*)
----------
37Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 NESTED LOOPS
3 2 TABLE ACCESS (FULL) OF 'T2'
4 2 INDEX (UNIQUE SCAN) OF 'PK_T1' (UNIQUE)SQL> SELECT COUNT(*) FROM T2, T1 WHERE T1.TABLE_NAME = T2.TABLE_NAME;
COUNT(*)
----------
37Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT ptimizer=CHOOSE
1 0 SORT (AGGREGATE)
2 1 NESTED LOOPS
3 2 TABLE ACCESS (FULL) OF 'T2'
4 2 INDEX (UNIQUE SCAN) OF 'PK_T1' (UNIQUE)僅僅是給T1增加了一個主鍵,就發現不管SQL語句怎么寫驅動表都是T2。
即使是RBO,確定表連接順序的規則也是比較復雜的:
1.優化器產生一系列連接順序,每次均把不同的表作為驅動表。而且,優化器根據下面的算法產生每個連接順序。
為了確定連接順序中各個表的位置,優化器根據RBO執行計划的排名,在剩余的表中找到表訪問路徑排名最高的表,然后不斷的重復這個過程,依次確定連接順序中每個表的前后順序。
對於連接順序中的每張表,優化器根據執行計划的排名選擇一種連接方式將當前表和前面的表或數據源連接在一起。
2.優化器在執行計划的結果集中進行選擇。
優化器的目標是最大程度的選擇內部表采用索引掃描方式的 NESTED LOOPS 連接操作。
通常情況下,優化器在選擇執行計划時,不會考慮表在FROM語句中出現的順序。
優化器依次根據下面的規則來作出選擇:
優化器選擇執行計划使得內部表為全表掃描的NESTED LOOPS連接盡可能的少;
如果采用上面的條件出現了平局的情況,則優化器選擇盡可能少出現SORT MERGE操作的執行計划;
如果仍然出現平局的情況,則優化器將選擇表訪問路徑中排名最高的表作為驅動表;
如果這時仍然是平局,則優化器會把 FROM 語句中最后出現的表最為驅動表