前两天在ITPUB看到这个问题,很多人有这个错误的概念,在RULE优化模式下,FROM语句中表的顺序连接的驱动表,但是事实上并不是这么简单。
其实RULE优化模式已经基本上退出了历史舞台,不过既然有人提起了,就把概念描述清楚,对RULE优化模式不感兴趣的可以无视这篇文章。
RULE方式是基于规则的,根据FROM列表中的顺序判断驱动表是规则之一,但是这个规则的优先级并不高,如果有其他优先级规则存在,则执行计划会发生改变:
SQL> CREATE TABLE T1
2 (ID NUMBER,
3 NAME VARCHAR2(30));
Table created.
SQL> CREATE TABLE T2
2 (ID NUMBER,
3 NAME VARCHAR2(30));
Table created.
SQL> INSERT INTO T1
2 SELECT ROWNUM, TNAME
3 FROM TAB;
95 rows created.
SQL> INSERT INTO T2
2 SELECT ROWNUM, TABLE_NAME
3 FROM DBA_TABLES;
8923 rows created.
SQL> COMMIT;
Commit complete.
下面将优化模式改为RULE模式,看看是否驱动表的选择与FROM列表中的位置有关:
SQL> ALTER SESSION SET OPTIMIZER_MODE = RULE;
Session altered.
SQL> SET AUTOT TRACE
SQL> SELECT *
2 FROM T1, T2
3 WHERE T1.ID = T2.ID;
95 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1792967693
------------------------------------
| Id | Operation | Name |
------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | MERGE JOIN | |
| 2 | SORT JOIN | |
| 3 | TABLE ACCESS FULL| T2 |
|* 4 | SORT JOIN | |
| 5 | TABLE ACCESS FULL| T1 |
------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID"="T2"."ID")
filter("T1"."ID"="T2"."ID")
Note
-----
- rule based optimizer used (consider using cbo)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
30 consistent gets
0 physical reads
0 redo size
4545 bytes sent via SQL*Net to client
558 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
95 rows processed
SQL> SELECT *
2 FROM T2, T1
3 WHERE T1.ID = T2.ID;
95 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 412793182
------------------------------------
| Id | Operation | Name |
------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | MERGE JOIN | |
| 2 | SORT JOIN | |
| 3 | TABLE ACCESS FULL| T1 |
|* 4 | SORT JOIN | |
| 5 | TABLE ACCESS FULL| T2 |
------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID"="T2"."ID")
filter("T1"."ID"="T2"."ID")
Note
-----
- rule based optimizer used (consider using cbo)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
30 consistent gets
0 physical reads
0 redo size
4545 bytes sent via SQL*Net to client
558 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
95 rows processed
可以看到,RULE优化器确实根据FROM列表中的位置来选择驱动表,FROM列表中最后一个表被作为驱动表。
但是这只是没有其他优先级更高的规则存在下的情况,只要在表中建立索引,就会导致优先级发生变化,从而导致上面的驱动表选择发生变化:
SQL> CREATE INDEX IND_T1_ID ON T1(ID);
Index created.
SQL> SELECT *
2 FROM T2, T1
3 WHERE T1.ID = T2.ID;
95 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3280696534
-------------------------------------------------
| Id | Operation | Name |
-------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 |
| 2 | NESTED LOOPS | |
| 3 | TABLE ACCESS FULL | T2 |
|* 4 | INDEX RANGE SCAN | IND_T1_ID |
-------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID"="T2"."ID")
Note
-----
- rule based optimizer used (consider using cbo)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
54 consistent gets
0 physical reads
0 redo size
4545 bytes sent via SQL*Net to client
558 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
95 rows processed
根据规则T1应该是驱动表,但是建立索引后,索引扫描的优先级远高于全表扫描,因此Oracle选择T2作为驱动表,将T1的执行计划变成了索引扫描。
T2上也存在索引,高优先级的规则对于驱动表的选择上条件等同,这时RULE优化器则又会根据FROM列表来判断驱动表:
SQL> CREATE INDEX IND_T2_ID ON T2(ID);
Index created.
SQL> SELECT *
2 FROM T2, T1
3 WHERE T1.ID = T2.ID;
95 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3621112097
-------------------------------------------------
| Id | Operation | Name |
-------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| T2 |
| 2 | NESTED LOOPS | |
| 3 | TABLE ACCESS FULL | T1 |
|* 4 | INDEX RANGE SCAN | IND_T2_ID |
-------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID"="T2"."ID")
Note
-----
- rule based optimizer used (consider using cbo)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
132 consistent gets
1 physical reads
0 redo size
4545 bytes sent via SQL*Net to client
558 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
95 rows processed
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/4227/viewspace-667851/ ,如需转载,请注明出处,否则将追究法律责任。