当前位置: 代码迷 >> 综合 >> 基于Oracle的SQL优化--学习(十四)
  详细解决方案

基于Oracle的SQL优化--学习(十四)

热度:27   发布时间:2023-09-19 15:22:38.0

子查询展开

    子查询展开(SubqueryUnnesting)是优化器处理带子査询的目标SQL的一种优化手段,它是指优化器不再将目标SQL中的子查询当作一个独立的处理单元来单独执行,而是将该子査询转换为它自身和外部查询之间等价的表连接。这种等价表连接转换要么是将子查询拆开(即将该子查询中的表、视图从子查询中拿出来,然后和外部査询中的表、视图做表连接),要么是不拆开但是会把该子査询转换为一个内嵌视图(InlineView),然后再和外部查询中的表、视图做表连接。
    Oracle会确保子查询展开所对应的等价表连接转换的正确性,即转换后的SQL和原SQL在语义上一定是等价的。当然,不是所有的子查询都能做子查询展开,有些子查询是不能做这种等价表连接转换的,这种情况下Oracle就不会对其做子查询展开,也就是说此时Oracle还是会将该子查询当作一个独立的处理单元来单独执行。另外,在Oracle10g及其以后的版本中,对于那种不拆开子查询但是会把该子查询转换成一个内嵌视图的子查询展开(即子查询展开的第二种情形),只有当经过子查询展开后的等价改写SQL的成本值小于原SQL的成本值时,Oracle才会对原SQL执行子查询展开。

    子査询展开通常都会提高原SQL的执行效率,因为如果原SQL不做子查询展开,那么通常情况下该子查询就会在其执行计划的最后一步才被执行,并且会走FILTER类型的执行计划,这也就意味着对于外部查询所在结果集中的每一条记录,该子查询都会被当作一个独立的执行单元来执行一次,外部查询所在的结果集有多少条记录,该子查询就会被执行多少次(可以近似这么理解,实际上并不完全是这样)。这种执行方式的执行效率通常情况下都不会太高,尤其是在子查询中包含两个或者两个以上表连接时,此时做子查询展开后的执行效率往往会比走FILTER类型的执行计划高很多,因为此时优化器就会有其他更多、更高效的执行路径(比如哈希连接)可以选择。
    Oracle数据库里子查询前的where条件如果是如下这些条件之一,那么这种类型的目标SQL在满足了一定的条件后就可以做子查询展开:
    (1)SINGLE-ROW(即=、<、>、<=、>=和?)
    (2)EXISTS
    (3)NOTEXISTS
    (4)IN
    (5)NOTIN
    (6)ANY
    (7)ALL
     如果一个子查询前的where条件是SINGLE-ROW条件,则意味着该子查询的返回结果至多只会返回一条记录;如果该子査询前的where条件是除SINGLE-ROW条件之外的上述其他类型的条件,则该子查询的返回结果就可以包含多条记录。ANY和ALL通常和SINGLE-ROW条件联用,虽然这两个条件我们不常用,但它们的应用范围其实比EXISTS、NOTEXISTS、IN和NOTIN要广很多,比如IN实际上就相当于=ANY,NOT IN实际上就相当于<> ALL。
    子査询是否能做子杳询展开取决于如下两个条件:
    (1)了査询展开所对应的等价改写SQL和原SQL在语义上一定要是完全等价的。如果改写后的SQL和原SQL并不一定能保持语义上的完全等价,这种类型的子查询就不能做子查询展开
    (2)对于不拆开子杳询但是会把它转换为一个内嵌视图的子査询展开,只有当经过子查询展开后的等价改写SQL的成本值小于原SQL的成本值时,Oracle才会对0标SQL执行子查询展开。
    需要注意的是,对于子査询展开的第一种情形(即将子査询拆开,把该子査询中的表、视图从子査询中拿出来,然后和外部査询中的表、视图做表连接),即使是在Oracle10g及其以后的版本中,Oracle也不会考虑子査询展开的成本,即Oracle此时会认为这种情形下子査询展开的效率始终比不展开的效率要离,这也就意味着如果目标SQL满足子査询展开的第一种情形,则Oracle始终会对其做子査询展开,而不管经过子查询展开后的等价改写SQL的成本值是否小于原SQL的成本值。

视图合并

    视图合并(ViewMerging)是优化器处理带视图的目标SQL的一种优化手段,它是指优化器不再将目标SQL中视图的定义SQL语句当作一个独立的处理单元来单独执行,而是会将其拆开,把其定义SQL语句中的基表拿出来与外部査询中的表合并,这样合并后的SQL将只剩下外部查询中的表和原视图中的基表,不再会有视图出现。

    Oracle会确保视图合并的正确性,即合并后的SQL和原SQL在语义上一定是完全等价的。当然,不是所有的视图都能做视图合并,有些视图是不能做视图合并的,这种情况下Oracle就会将该视图的定义SQL语句当作一个独立的处理单元来单独执行。视图合并的好处和子查询展开一样,都是让优化器有更多的执行路径可以选择,而不再拘泥于原视图定义QL语句中的谓词条件、表连接方法、表连接顺序等。    

    Oracle数据库里的视图合并分为简单视图合并、外连接视图合并和复杂视图合并这三种类型。对于符合简单视图合并条件的目标SQL,Oracle始终会对其做视图合并,而不管经过视图合并后的等价改写SQL的成本值是否小于原SQL的成本值。但在Oracle10g及其以后的版本中,对于复杂视图合并,只有等价改写SQL的成本值小于原SQL的成本值时,Oracle才会对目标SQL做复杂视图合并。
简单视图合并

    简单视图合并(SimpleViewMerging)是指针对那些不含外连接,以及所带视图的视图定义SQL语句中不含distinct、groupby等聚合函数的目标SQL的视图合并。

外连接视图合并

    外连接视图合并(OuterJoinViewMerging)是指针对那些使用了外连接,以及所带视图的视图定义SQL语句中不含distinct、groupby等聚合函数的目标SQL的视图合并。这里“使用外连接”的含义是指外部查询的表和视图之间使用了外连接,或者该视图的视图定义SQL语句中使用了外连接。

    外连接会给视图合并带来很多限制,很多在内连接情形下可以做的视图合并一旦换成了外连接就不能做了,因为Oracle能做视图合并的前提条件就是视图合并后的等价改写SQL—定要和原SQL在语义上是完全等价,但对于使用了外连接的目标SQL而言,在很多情况下这种语义上的完全等价性并不能得到保证。
    关于外连接视图合并有一个很常用的限制,即当目标视图在和外部查询的表做外连接时,该目标视图可以做外连接视图合并的前提条件是,要么该视图被作为外连接的驱动表,要么该视图虽然被作为外连接的被驱动表但它的视图定义SQL语句中只包含一个表。



  相关解决方案