sql 字段相同取其中一条_ABAP程序效率优化——一个简单的SQL竟然如此坑爹……...

一个简单的需求,一个简单的SQL,执行起来竟慢的可怕。原因为何,如何解决,看我慢慢道来。

本文目录如下:

1、需求;2实现;3-11、问题分析解决;12总结

(1/12)需求


根据项目号,取WBS,然后根据AUFK~PSPEL=WBS,取AUFK和AFKO的数据。同时还需要根据WBS取一些额外的其他数据。

(2/12)实现


因为WBS还有它用,所以我先取出WBS,放到内表GT_PRPS中。

接下来,取AUFK和AFKO的逻辑如下:

ab3d05324a9c66a7e6d7cf1f6ef110b0.png

(3/12)问题-第一步


执行时,发现执行的非常慢,然后用ST05(使用说明参见这里)进行执行计划分析,结果如下:

b24db66862e3dd156b9f510aa9507e83.png

(4/12)问题解释-第一步


慢的原因有两个:

1、看上面where条件中,PSPEL IN中只有5个值,而我的GT_PRPS中条目数(是全都不重复的),共有上万条。这样就相当于,这条语句要执行2000多次

2、下面红框框出来的部分,TABLE ACESS FULL AKFO。在AFKO和AUFK关联的时候,用的是AUFNR,这个字段是这两个表的主键。不知道为什么,这里没有通过主键的索引取值,而是执行了全表扫描。

擦嘞,这坑爹的执行计划!

(5/12)解决方案-第一步


为解决上述两个问题:

1、当for all entries in的内表,只用到一个字段时,使用hints改变SQL执行计划中IN的条目数

2、使用hints指定用表的哪个索引。为防止AUFK也出现不使用索引的情况,在此也为AUFK指定索引。

如下图:

3ea452684bfa44c585193f0775b34a71.png

解释如下:

1、T_00为AUFK,T_01为AFKO。AUFK~D为AUFK中包含PSPEL字段的索引,AFKO~0为AFKO的主键索引

2、prefer_in_itab_opt指定为1,表示将GT_PRPS中的值转为WHERE ... IN ..的方式,max_in_blocking_factor表示每个IN中最大的条目数,这极有效的减少了SQL执行的数量。

(6/12)问题-第二步


本以为执行结果应该正常,但是ST05的执行计划却如下:

b3ccaba19e65bf955faaffebbcbc007e.png

(7/12)问题解释-第二步


ST05的执行计划显示,数据库首先进行了AFKO的SCAN,然后再进行了AUFK的SCAN。但是我们的查询条件是AUFK的PSPEL,这不符合我们的要求。所以,还是需要继续干预一下SQL的执行计划。

【注意:我也可以不通过AUFK和AFKO JOIN的方式来取数,改为两次for all entries in(先from aufk,再from afko),但是需要定义额外的内表,并进行数据处理。而且我的目的是要优化这个简单SQL的执行计划】

(8/12)解决方案-第二步


干预SQL的执行计划,让它按照表出现的顺序来执行。

a15c5a3a1435afc26806da2131b192e9.png

【此处,ordered也可以用leading代替。leading表示先访问AUFK,ordered表示按照AUFK、AFKO的顺序访问】

(9/12)问题-第三步


再次执行,查看执行计划,发现顺序是没问题了,但是执行计划中,表AFKO~0这个索引的使用方式存在问题。

451c803f383165ae0cccca2f1cd39825.png

(10/12)问题解释-第三步


查看AFKO~0的索引如下,包括MANDT和AUFNR两个字段:

98dc17844749baab4d0d5cbe94411631.png

数据库在ACCESS AFKO时,却只用到了索引中的MANDT,这没什么卵用啊。

67b4ca162a52a4fe45711c9f80459659.png

再看6Hash Join时,才将AFKO和AUFK的数据进行匹配处理。

32c59f4a2d6fb9fb2aaa37234a2e093d.png

(11/12)解决方案-第三步


我初步猜测是因为JOIN的方式影响的,这种情况下,一般常见的都是NESTED LOOPS的JOIN方式。

于是,我写一个更简单的SQL来验证一下。

DATA: GT_AFKO TYPE TABLE OF AFKO.

SELECT * INTO CORRESPONDING FIELDS OF TABLE GT_AFKO

FROM AUFK INNER JOIN AFKO ON AFKO~AUFNR = AUFK~AUFNR

WHERE PSPEL = '00000001'.

然后ST05查看其执行计划,如下图:

49500ce100c9c66a48131a1aaba56a8a.png

果然,是NESTED LOOPS。

于是我继续加一个hints来干预执行计划,如下:

801ce71e3cc0998ecb76a78c3782abf4.png

指定这两个表通过NESTED LOOP的方式关联。

【更多关于use_nl和use_hash的用法,请自行谷歌百度】

再次跟踪SQL执行计划,得到结果如图:

25d3e34e91d416115ddf02a8b1cdc416.png

(12/12)最后


我尝试换了一些别的系统,执行同样的最初的SQL(不加HINTS的),SQL执行计划各不相同。所以本文仅是针对特定数据库环境下的特殊结果,进行的执行计划分析与执行计划优化,供猿们探讨交流。


297f41f65e7b58f0462bc6ba964f9dfc.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值