解决Oracle SQL语句性能问题——SQL语句改写(视图、标量子查询及update)

我们在前述文章中也已经提到,对于高版本的关系库,尤其是针对Oracle这样的关系库,绝大多数场景下,同一语义和结果的SQL语句的具体语法,不会成为SQL语句执行计划的影响因素,但在少数场景下,针对同一语义和结果的SQL语句的不同写法,数据库优化器最终会分别为其生成不同的执行计划。因此,当一条SQL语句的执行计划不理想时,为了改变该SQL语句的执行计划,我们会考虑改写相应SQL语句,从而达到调优目的。下面,具体介绍通过SQL语句改写进行调优的方法和相关内容。

1. 消除视图(view

视图可以简化应用的研发和维护,还可以满足安全性方面的需求。但在有些场景中,视图会为应用埋下性能隐患,尤其在大数据量业务中,大量且多层次嵌套使用视图的场景。为了消除性能隐患和优化性能,有时需要我们改写包含视图的SQL语句,分解并消除其中的相关视图,具体改写方法如下所示。

--改写前

SQL> create view v_test as

select * from tab1 where col1=...;

SQL> select * from tab2 t2,tab3 t3,v_test v

where t2.col1=t3.col1

and t3.col1=v.col1

and v.col2=...;

--改写后

SQL> select * from tab2 t2,tab3 t3,tab1 t1

where t2.col1=t3.col1

and t3.col1=t1.col1

and t1.col2=...

and t1.col1=...;

--注:

      1)消除视图时需要注意的事项。

  • 是否符合视图分解和消除条件,有些场景的视图,是没办法分解和消除的。
  • 要把和原视图相关的select list中相关项,更换为原视图相应基表的列名。
  • 要把原视图内的where条件和主查询合并。
  • 要把原主查询中视图相关的条件更换为视图相应基表列的相关条件。

      2)消除视图的适用场景,包括但不限于如下场景。

  • 原SQL语句主查询from中连接数据对象比较多,且原SQL语句存在性能问题。
  • 原SQL语句的视图子查询from中连接数据对象比较多,且原SQL语句存在性能问题。
  • 原SQL语句中视图嵌套层数比较多,且原SQL语句存在性能问题。

      3)设计实验并做测试。

  • 获取分解消除视图前后的执行计划,并比较思考分解消除视图前后的变化和利弊。
  • 注意分解消除视图前后,执行计划中join相关节点(见本书第7章)的变化,执行计划的整体调整和变化。
  • 如果分解消除视图前后的执行计划没有变化,大家思考下,没有发生变化的原因,以及导致可能发生变化的场景和因素。

2. 标量子查询改为外连接

包含标量子查询的SQL语句,看上去思路清晰、逻辑分明且易于理解,但在很多场景中,标量子查询会导致其相关SQL语句的严重性能问题。因此,为了解决相关SQL语句的性能问题,有时我们需要对SQL语句进行改写,并消除相关的标量子查询,以对相关SQL语句进行性能优化,具体改写方法如下所示。

--改写前

SQL> select t1.col1,

(

select col2

from

(

select t2.col1,sum(t2.col2) col2 

from tab2 t2

group by t2.col1

) t3 

where t3.col1=t1.col2

) col2_sum

from tab1 t1

where t1.col3=...;

--改写后

SQL> select t1.col1,t3.col2 col2_sum

from tab1 t1,

(

select t2.col1,sum(t2.col2) col2 

from tab2 t2

group by t2.col1

) t3

where t1.col2=t3.col1(+)

and t1.col3=...;

--注:

      1)标量子查询改写为内嵌视图时需要注意的事项。

  • 是否符合改写和消除标量子查询的条件。
  • 原标量子查询下沉为内嵌视图时,需要和原主查询表进行outer join。
  • 原SQL语句中存在多个标量子查询时,应该分别改为相应内嵌视图并下沉,同时,分别和原主查询表进行outer join。
  • 原SQL语句中存在多个标量子查询时,分别改为相应内嵌视图,下沉并进行outer join后,原主查询select-list中各标量子查询相关的列,改为相应内嵌视图的列。

      2)标量子查询改写为内嵌视图的适用场景,包括但不限于如下场景。

  • 原SQL语句中包含标量子查询,且原SQL语句存在性能问题。
  • 原SQL语句中包含标量子查询,且原SQL语句消耗较多系统资源。

      3)设计实验并做测试。

  • 获取改写和消除标量子查询前后的执行计划,并比较分析改写和消除标量子查询前后的变化和利弊。
  • 注意观察分析相关SQL语句改写前后,子查询执行次数的变化和执行计划的整体变化。

3. update改为merge into

update作为DML语句之一,现实工作中,被数据库及研发相关人员广泛使用。但在某些场景中,update语句会导致严重的性能问题。基于上述场景,为了解决update语句导致的性能问题,有时我们需要将update语句改写为merge into语句,以消除导致性能问题的因素,优化和提升相关应用性能。

2014年,某行业机构相关人员对线上产品某核心模块重构、测试后,按计划在生产环境中进行替换,不料,期间发生严重性能问题,导致整个应用系统异常,用户无法使用。本人接到技术支援求助后,连夜通过该数据库的相关信息进行问题跟踪、分析和诊断,确定该故障由重构后的新应用模块导致,并在各方相关人员的协助下,在线对生产环境中该应用模块进行了修改和替换,即将该模块中一个update语句修改为merge into语句。之后,经本人和相关各方人员跟踪和观察,之前性能问题消失,相关应用模块性能提升近千倍。

此外,除了解决性能问题,某些场景中,merge into语句也能很好的解决某些特殊的业务需求。2016年,通过merge into语句,本人帮助某行业机构产品研发团队成功解决了跨时段详单汇聚问题,这样,既避开了原计划在大数据量、高并发频繁操作的核心业务表上,建立触发器可能带来性能等多方面问题的风险,又大幅提高了相应模块的性能,简化了应用逻辑和实现方法,为今后系统的管理和维护打下了良好的基础。关于update语句改写为merge into语句,具体改写方法如下所示。

--改写前

SQL> update tab1 t1 set col2=

(

select col2

from tab2 t2

where t1.col1=t2.col1

)

where t1.col3=...;

--改写后

SQL> merge into tab1 t1

using tab2 t2

on

(

t1.col1=t2.col1

)

when matched then

update set t1.col2=t2.col2

where t1.col3=...;

--注:

      1)update语句改写为merge into语句时需要注意的事项。

  • 是否符合update语句改为merge into语句的改写条件。
  • 确定好两个行源的关系,并按照merge into语句的语法确保进行正确的修改。
  • 确定好两个行源的连接条件,并按照merge into语句的语法确保进行正确的修改。
  • 高版本Oracle中,对merge into语句功能提供了更加强大的支持,具体请参考官方或其他相关文档。

      2)update语句改写为merge语句的适用场景,包括但不限于如下场景。

  • update语句中存在相关子查询,且update语句存在性能问题。
  • 必须通过merge into语句来解决某些特殊的业务需求。

      3)设计实验并做测试。

  • 获取update语句改写为merge into语句前后的执行计划,并比较分析改写前后的变化和利弊。
  • 注意观察分析update语句改写为merge into语句前后,原相关子查询执行次数的变化和执行计划的整体变化。
  • 请大家编写一条merge into语句,其中,既完成update操作,也完成insert等多个操作。

      4)大家可以在update语句改写为merge into语句,与改写及消除标量子查询之间,比较和分析两者的区别和联系。

      5)大家思考和实验,是否可以用解决标量子查询性能问题的办法来解决该update语句的性能问题,并比较分析其中原因。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lhdz_bj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值