LEADING提示的作用和使用方法

LEADING提示是指导优化器,尽量先访问指定的表或表的集合。该提示相较于ORDERED提示更灵活。

LEADING提示的使用语法如下图所示:

Oracle Hint(提示)之LEADING_sql优化


其中:

tablespec表示目标表的名称或别名(当有别名时,必须用别名)。但不要加入表的属主(SCHEMA)名,哪怕在SQL中,明确写了属主,提示中也不能写。

queryblock表示查询块。优化器在为一条SQL制定执行计划时,会将该SQL中涉及的子查询和视图,拆分为相应的查询块。分别为每一个查询块制定执计划。

下面,我们通过实验来说明施加该提示时,优化器是如何选择表的访问次序的。

测试验证

首先,我们创建两个测试表TAB1、TAB2:

Oracle Hint(提示)之LEADING_sql优化_02

并在其上收集统计信息,如下图所示:

Oracle Hint(提示)之LEADING_sql优化_03

然后我们在其这两个表上执行如下的查询:

select count(*) 
from tab1,tab2
where tab1.object_id=tab2.object_id;

当我们什么提示都不加时,其执行计划如下:

Oracle Hint(提示)之LEADING_oracle_04

如上图所示,此时是先访问TAB1表,然后才是TAB2表。

下面,我们使用LEADING提示,让优化器考虑先访问TAB2表。如下图所示:

Oracle Hint(提示)之LEADING_hint_05

但是,当我们提供了多个LEADING提示时,优化器会忽略所有的LEADING提示。如下图所示:

Oracle Hint(提示)之LEADING_oracle_06


如上所示,并不是如提示中所期望的,先访问TAB2表,再访问TAB1表。那是否可能是优化器在处理提示时,是从后往前处理,即,先处理leading(tab1),再处理leading(tab2)。如果是这样的话,那么上面的执行计划,就是预期的执行计划。

为了验证这一点,我们交换两个LEADING的次序,让LEADING(TAB1)在前,LEADING(TAB2)在后,如果猜测成立,那么应该是先访问TAB2,再访问TAB1。测试结果如下:

Oracle Hint(提示)之LEADING_oracle_07

如上所示,证明我们的猜测是不成立的。实际上,这是由于两个leading提示发生了冲突,一个让优化器把TAB1做为驱动表,而另一个让优化器把TAB2做为驱动表,这显然是矛盾的。

同理,LEADING提示与ORDERED提示一同使用时,也会导致LEADING提示被忽略。即可以理解为,ORDERED提示的优先级高于LEADING提示。测试过程如下:

Oracle Hint(提示)之LEADING_oracle_08

如上所示,我们可以看到并不是先访问的TAB2表。

当我们需要指定多张表优先访问时,需要在一个LEADING提示中进行指定。如下所示:

Oracle Hint(提示)之LEADING_hint_09

如上所示,我们在LEADING提示中,指定按先访问TAB3表,再访问TAB2表的次序进行。(注:上面的TAB3表的创建方法与TAB1和TAB2表的创建方法类似,故这里不再赘述。),但我们从执行计划中,虽然看到的是先访问了TAB1表,然后才是访问TAB3和TAB2表,只是在访问TAB3和TAB2表时,先访问的是TAB3,后访问的是TAB2。那是不是我们把TAB1也加到LEADING提示中,并且放到最后,就能走出先访问TAB3,再访问TAB2,最后访问TAB1的结果呢?测试结果如下:

Oracle Hint(提示)之LEADING_sql优化_10


如上图所示,我们可以看到并没有如我们预期那样,TAB1表放到最后访问。所以,从这里,我们也要注意到,提示(HINT)并不是强制的行为,优化器有时,并不一定会按照提示中期望的那样行事。有时,还需要配合一些其它提示,来完成预期的行为。比如上例,我们需要再添加一个 no_swap_join_inputs(tab1)的示,才可以实现我们预期的行为,如下图所示:

Oracle Hint(提示)之LEADING_oracle_11

知识总结

1、LEADING提示是指导优化器,按照指定的次序来访问表。
2、当需要指定多张表时,需要写在一个LEADING提示中,不要写多个LEADING提示。写多个LEADING提示,会导致全部的LEADING提示被忽略。
3、LEADING提示的优化级低于ORDERED提示,当两个提示出现时,LEADING提示会被忽略。