last_name字段有索引,但在查询中使用了函数,因此该查询不会使用索引。如果想让这个查询走索引,则需要建立函数索引create index ind_upper_lastname on last_name (upper(last_name))。特别要注意的是隐式转换,比如colx字段是varchar2型但存放数字:where colx=123456,这时会发生隐式转换TO_NUMBER(colx),此时colx上的索引也会失效。
通常情况下散列连接的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。可以使用USE_MERGE(table_name1 table_name2)来强制使用排序合并连接。 以下情况Oracle可能会选择使用排序合并连接: l 两个表做非等值连接 l OPTIMIZER_MODE被设置成RULE l HASH_JOIN_ENABLE设置成FALSE l 已经事先排过序,优化器认为使用排序合并连接的成本要比散列连接低。 l HASH_AREA_SIZE和SORT_AREA_SIZE设置太小,优化器认为散列连接成本过高。
外连接
不论是嵌套循环外连接还是散列外连接,CBO不会根据成本去选择连接顺序,被驱动的表总是含有(+)的一方。 SQL> select /*+ordered use_nl(t1 t2)*/ t1.msisdn,t2.msisdn from t1,t2 where t1.msisdn(+)=t2.msisdn; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=100 Card=99 Bytes=2178) 1 0 NESTED LOOPS (OUTER) (Cost=100 Card=99 Bytes=2178) 2 1 INDEX (FULL SCAN) OF 'IND_T2' (NON-UNIQUE) (Cost=1 Card=99 Bytes=1089) 3 1 INDEX (RANGE SCAN) OF 'IND_T1' (NON-UNIQUE) (Cost=1 Card=1 Bytes=11)
虽然使用了ORDERED提示,试图以t1作为驱动表,可是由于是外连接,仍然是以t2作为驱动表。 换成散列连接也是一样: SQL> select /*+ordered use_hash(t1 t2)*/ t1.msisdn,t2.msisdn from t1,t2 where t1.msisdn(+)=t2.msisdn; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=99 Bytes=2178) 1 0 HASH JOIN (OUTER) (Cost=4 Card=99 Bytes=2178) 2 1 INDEX (FULL SCAN) OF 'IND_T2' (NON-UNIQUE) (Cost=1 Card=99 Bytes=1089) 3 1 INDEX (FAST FULL SCAN) OF 'IND_T1' (NON-UNIQUE) (Cost=2 Card=999 Bytes=10989) 此时,外表为t1,内表为t2,连接保留t1表与t2不匹配的行,然后用t1构建散列表,最后由t2表去探测t1生成的散列表。
Full Outer Joins
select t1.msisdn,t2.msisdn from t1 full outer join t2 on t1.msisdn=t2.msisdn order by t2.msisdn
Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=15 Card=1000 Bytes=36000) 1 0 SORT (ORDER BY) (Cost=15 Card=1000 Bytes=36000) 2 1 VIEW (Cost=6 Card=1000 Bytes=36000) 3 2 UNION-ALL 4 3 NESTED LOOPS (OUTER) (Cost=2 Card=999 Bytes=21978) 5 4 INDEX (FAST FULL SCAN) OF 'IND_T1' (NON-UNIQUE) (Cost=2 Card=999 Bytes=10989) 6 4 INDEX (RANGE SCAN) OF 'IND_T2' (NON-UNIQUE) 7 3 HASH JOIN (ANTI) (Cost=4 Card=1 Bytes=22) 8 7 INDEX (FULL SCAN) OF 'IND_T2' (NON-UNIQUE) (Cost=1 Card=99 Bytes=1089) 9 7 INDEX (FAST FULL SCAN) OF 'IND_T1' (NON-UNIQUE) (Cost=2 Card=999 Bytes=10989) 从执行计划看,实际上就是做了两个外连接,一个是t1.msisdn=t2.msisdn(+)走嵌套循环,一个是t1.msisdn(+)=t2.msisdn走散列连接,然后再UNION-ALL两个行集。 结果像下面这样: