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

本文目录如下:

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


(1/12)需求


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


(2/12)实现


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

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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_sql


(3/12)问题-第一步


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_sql_02


(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指定索引。

如下图:

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_执行计划_03

解释如下:

1、T_00为AUFK,T_01为AFKOAUFK~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的执行计划却如下:

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_执行计划_04


(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的执行计划,让它按照表出现的顺序来执行。

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_执行计划_05

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


(9/12)问题-第三步


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_sql_06


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


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_sql_07


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_字段_08


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_字段_09


(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查看其执行计划,如下图:

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_执行计划_10

果然,是NESTED LOOPS。


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_执行计划_11

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

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


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

ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_sql_12


(12/12)最后


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



ABAP程序效率优化——一个简单的SQL竟然如此坑爹……_执行计划_13