|
to remen :正如Yong Huang所说在PL/SQL块中的提示,在'+'后面必须跟一个空格。这是很重要的,否则提示可能会被忽略,因为一些版本的 PL/SQL在把查询传给SQL引擎的时候,会忽略掉'+'号后面的第一个字符。但是直接写的SQL应该不需要吧
to Yong Huang:我把你的话做了个总结
(1)首先是2张表的情况:
SQL> set autotrace traceonly
SQL> select /*+ use_hash(t_middle) */ * from t_middle,t_min where t_middle.object_id = t_min.object_id ;
已选择55行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=44 Card=56 Bytes=161
28)
1 0 HASH JOIN (Cost=44 Card=56 Bytes=16128)
2 1 TABLE ACCESS (FULL) OF 'T_MIN' (Cost=2 Card=56 Bytes=896
0)
3 1 TABLE ACCESS (FULL) OF 'T_MIDDLE' (Cost=39 Card=24069 By
tes=3080832)
Statistics
----------------------------------------------------------
268 recursive calls
0 db block gets
445 consistent gets
397 physical reads
0 redo size
8284 bytes sent via SQL*Net to client
536 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
55 rows processed
SQL> select /*+ use_hash(t_middle) */ * from t_min,t_middle where t_middle.object_id = t_min.object_id ;
已选择55行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=44 Card=56 Bytes=161
28)
1 0 HASH JOIN (Cost=44 Card=56 Bytes=16128)
2 1 TABLE ACCESS (FULL) OF 'T_MIN' (Cost=2 Card=56 Bytes=896
0)
3 1 TABLE ACCESS (FULL) OF 'T_MIDDLE' (Cost=39 Card=24069 By
tes=3080832)
Statistics
----------------------------------------------------------
6 recursive calls
0 db block gets
418 consistent gets
299 physical reads
0 redo size
8284 bytes sent via SQL*Net to client
536 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
55 rows processed
从这儿可以看出use_hash(t_middle)并没有将t_middle指定为驱动表,应该是根据你说的oracle由cardinality决定哪张表作为hash table,这里可以看出是将t_min做为hash table,然后扫描表t_middle,并通过hash算法探测刚建成的hash table(由表t_min建立的),找出匹配的行。
在这里我认为哪张表在内存中建立了hash table,那么它就是驱动表(driving table),在这个例子里就是t_min。
这点好像与Yong Huang大师上面的一句话有出入“So why did you get the above plan when you have ordered and use_hash and tables are t_max, t_middle and t_small in that order? Here, t_max is first hashed into memory (build table), as dictated by the ordered hint. t_middle is the driving i.e. probe table (each row of it is taken out, compute its hash value, check the in-memory hash table built earlier for t_max to find a match). ”在大师引用的例子中,首先t_max表为hash table这个是肯定的,因为使用了ordered hint。但是大师好像认为t_middle为驱动表(t_middle is the driving),这个观点我不认同,t_middle只是探测表(probe table),驱动表(driving table)应该是t_max。不知我理解的对不对,希望大师帮助。
最后如果你想让t_max在内存中建里hash table(即让t_max为驱动表),这是使用Hint ordered就可以了,因为ordered使用from子句中的表的顺序进行表连接。
SQL> select /*+ordered use_hash(t_max) */ * from t_max,t_min where t_max.object_id = t_min.object_id ;
已选择55行。
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=127 Card=56 Bytes=18
872)
1 0 HASH JOIN (Cost=127 Card=56 Bytes=18872)
2 1 TABLE ACCESS (FULL) OF 'T_MAX' (Cost=42 Card=17681 Bytes
=3129537)
3 1 TABLE ACCESS (FULL) OF 'T_MIN' (Cost=2 Card=56 Bytes=896
0)
Statistics
----------------------------------------------------------
6 recursive calls
0 db block gets
441 consistent gets
476 physical reads
0 redo size
9294 bytes sent via SQL*Net to client
536 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
55 rows processed
ps:
Yong Huang:What if you add swap_join_inputs(t_small)? If the plan stays the same as above, it just guarantees this plan's stability. If t_small drops to the bottom, I'll be surprised.
使用swap_join_inputs(t_small)不会产生t_small drops to the bottom这种情况,因为 swap_join_inputs(tabX) forces tabX to be the build (first) table in the join,也就是说使用这个hint,会将t_small表作为内存中的hash table,而这与没有使用这个hint的原来的计划没有变化,所以不会出现t_small drops to the bottom这种情况。
但是如果执行计划中t_small本身就在最后(不是hash table),那么使用这个hint会将t_small表变成hash table(驱动表)。
the end:
超过2张表时,ordered hint好像会有问题,关于多张表的连接的详细测试,我稍后补上。
[ 本帖最后由 iso90000 于 2008-4-30 15:00 编辑 ] |
|