LOOP itab vs VALUE FOR 过滤,哪个更高效?

问题描述

我正在尝试为以下场景编写一个 for 循环语句:

我使用选择将多个 tvarvc 条目数据放入 T_TVARVC

LOOP AT t_tvarvc INTO DATA(s_tvarvc).
    CASE s_tvarvc-name.
      WHEN c_augru.
        s_tvarvc_range = CORRESPONDING #( s_tvarvc ).
        APPEND s_tvarvc_range TO t_augru.

      WHEN c_vkorg.
        s_tvarvc_range = CORRESPONDING #( s_tvarvc ).
        APPEND s_tvarvc_range TO t_vkorg.
    ENDCASE.
ENDLOOP. 

这是我想出来的:

DATA(t_augru) = VALUE tt_tvarvc( FOR s_tvarvc IN t_tvarvc
                                  WHERE ( name = c_augru )
                                  ( CORRESPONDING #( s_tvarvc ) ) ).

DATA(t_vkorg) = VALUE tt_tvarvc( FOR s_tvarvc IN t_tvarvc
                                  WHERE ( name = c_vkorg )
                                  ( CORRESPONDING #( s_tvarvc ) ) ). 

我的观察是,通过使用 LOOP ATCASE 语句组合,迭代次数将与 T_TVARVC 中的条目数相同。
但是当对每个范围表使用 FOR 循环时,T_TVARVC 必须遍历更多次才能到达所需的条目,从而导致比第一种情况更多的迭代。

能否以更有效的方式编写?

解决方法

我同意你关于将迭代次数加倍的观察,为了让它更快,我认为唯一的解决方案是只使用一个循环,考虑到内部表尚未排序,这限制了很多可能的解决方案,并且我来到这个解决方案:

TYPES: tt_tvarvc TYPE STANDARD TABLE OF tvarvc WITH EMPTY KEY,BEGIN OF ty_ranges,t_augru TYPE tt_tvarvc,t_vkorg TYPE tt_tvarvc,END OF ty_ranges.
CONSTANTS: c_augru TYPE tvarvc-name VALUE 'AUGRU',c_vkorg TYPE tvarvc-name VALUE 'VKORG'.

DATA(t_tvarvc) = VALUE tt_tvarvc( for i = 1 while i <= 100 ( name = c_augru ) 
                                                           ( name = c_vkorg ) ).
DATA(ranges) = REDUCE ty_ranges(
                  INIT ranges2 = VALUE ty_ranges( )
                  FOR <tvarv> IN t_tvarvC
                  NEXT ranges2-t_augru = COND #( WHEN <tvarv>-name = c_augru
                                              THEN VALUE #( BASE ranges2-t_augru ( <tvarv> ) )
                                              ELSE ranges2-t_augru )
                       ranges2-t_vkorg = COND #( WHEN <tvarv>-name = c_vkorg
                                              THEN VALUE #( BASE ranges2-t_vkorg ( <tvarv> ) )
                                              ELSE ranges2-t_vkorg ) ).

(您将在代码中使用 ranges-t_augruranges-t_vkorg 而不是 t_augrut_vkorg

您可以立即看到代码比您的两个代码段中的任何一个都更不清晰。

此外,与经典循环相比,性能没有任何提升。

回到带有两次 FOR 迭代的代码段,我们可以看到与经典循环(我的观点)相比,目标非常明确。它当然更慢,但可能你不需要获得几微秒,所以我认为这是最好的解决方案(仍然是我的意见)。

,

只是添加与该部分相关的另一个答案

My observation is that,by using LOOP AT and CASE statement combo,the number of iterations will be same as the number of entries in T_TVARVC.
But when using a FOR loop for each range table,T_TVARVC has to be traversed more times to reach the desired entry thus causing multiple iterations more than the first scenario.

只有当您没有相关字段的排序索引时,这才是正确的。假设您使用 WHERE ( name = c_vkorg ) 而不是 USING KEY sk_name WHERE ( object = c_vkorg )。这将知道您正在搜索的值在 log n 时间开始的索引。然后它只会处理匹配键的行,从不循环其他任何东西。
这可能会节省大量时间。

索引 Val1 Val2 Val3(排序索引)
1 A 9999 AAA
2 B 1213 AAB
3 C 554 AAC
... ... ... ...
500 X 1 AUGUR

缺点是排序的辅助键也需要时间来构建(和一些内存)。如果您还有其他需要快速访问的代码,这可能不是问题。
辅助键是惰性的,所以第一次使用它们的时间就是它们将被创建的时间。

在你的场景中,你必须决定什么是值得的。是否有需要密钥的频繁读取访问?几行?因为其他地方不需要密钥,所以建立密钥访问是否更昂贵?二级密钥多久失效一次等等。

(注意:如果取消对 xsdbool 的注释,则从测量中排除构建辅助密钥所需的时间)。

REPORT ztest.

START-OF-SELECTION.
  PERFORM standard.
  PERFORM sorted_secondary.
  PERFORM sorted_secondary_val.

FORM standard.
  DATA t_tadir TYPE STANDARD TABLE OF tadir WITH EMPTY KEY.
  DATA t_clas TYPE STANDARD TABLE OF tadir-obj_name WITH EMPTY KEY.
  DATA t_tran TYPE STANDARD TABLE OF tadir-obj_name WITH EMPTY KEY.

  SELECT * FROM tadir UP TO 1000000 ROWS INTO TABLE @t_tadir ORDER BY PRIMARY KEY.
*  DATA(dummy) = xsdbool( line_exists( t_tadir[ key primary_key object = 'CLAS' ] ) ).

  GET RUN TIME FIELD DATA(t1).
  LOOP AT t_tadir ASSIGNING FIELD-SYMBOL(<s_tadir>).
    CASE <s_tadir>-object.
      WHEN 'CLAS'.
        APPEND <s_tadir>-obj_name TO t_clas.

      WHEN 'TRAN'.
        APPEND <s_tadir>-obj_name TO t_tran.
    ENDCASE.
  ENDLOOP.
  GET RUN TIME FIELD DATA(t2).
  WRITE: |{ ( t2 - t1 ) / '1000.0' / '1000.0' },{ lines( t_tadir ) },{ lines( t_clas ) },{ lines( t_tran ) }|.
  NEW-LINE.
ENDFORM.

FORM sorted_secondary.
  DATA t_tadir TYPE STANDARD TABLE OF tadir WITH NON-UNIQUE SORTED KEY sk_object COMPONENTS object.
  DATA t_clas TYPE STANDARD TABLE OF tadir-obj_name WITH EMPTY KEY.
  DATA t_tran TYPE STANDARD TABLE OF tadir-obj_name WITH EMPTY KEY.

  SELECT * FROM tadir UP TO 1000000 ROWS INTO TABLE @t_tadir ORDER BY PRIMARY KEY.
*  DATA(dummy) = xsdbool( line_exists( t_tadir[ key sk_object object = 'CLAS' ] ) ).

  GET RUN TIME FIELD DATA(t1).
  LOOP AT t_tadir ASSIGNING FIELD-SYMBOL(<s_tadir>) USING KEY sk_object WHERE object = 'CLAS'.
    APPEND <s_tadir>-obj_name TO t_clas.
  ENDLOOP.
  LOOP AT t_tadir ASSIGNING <s_tadir> USING KEY sk_object WHERE object = 'TRAN'.
    APPEND <s_tadir>-obj_name TO t_tran.
  ENDLOOP.
  GET RUN TIME FIELD DATA(t2).
  WRITE: |{ ( t2 - t1 ) / '1000.0' / '1000.0' },{ lines( t_tran ) }|.
  NEW-LINE.
ENDFORM.

FORM sorted_secondary_val.
  DATA t_tadir TYPE STANDARD TABLE OF tadir WITH NON-UNIQUE SORTED KEY sk_object COMPONENTS object.
  DATA t_clas TYPE STANDARD TABLE OF tadir-obj_name WITH EMPTY KEY.
  DATA t_tran TYPE STANDARD TABLE OF tadir-obj_name WITH EMPTY KEY.

  SELECT * FROM tadir UP TO 1000000 ROWS INTO TABLE @t_tadir ORDER BY PRIMARY KEY.
*  DATA(dummy) = xsdbool( line_exists( t_tadir[ key sk_object object = 'CLAS' ] ) ).

  GET RUN TIME FIELD DATA(t1).
  t_clas = VALUE #( for <fs> in t_tadir USING KEY sk_object WHERE ( object = 'CLAS' ) ( <fs>-obj_name ) ).
  t_tran = VALUE #( for <fs> in t_tadir USING KEY sk_object WHERE ( object = 'TRAN' ) ( <fs>-obj_name ) ).
  GET RUN TIME FIELD DATA(t2).
  WRITE: |{ ( t2 - t1 ) / '1000.0' / '1000.0' },{ lines( t_tran ) }|.
  NEW-LINE.
ENDFORM.

另外:LOOP AT ... ASSIGNING/REFERENCE INTO 可能比 LOOP AT ... INTO 快。由于您没有进行不应反映在原始数据源中的写访问,因此没有理由在每个循环步骤中复制每一行。

,

您也可以尝试专门的 FILTER 语句来实现相同的效果:

DATA lt_tadir TYPE SORTED TABLE OF tadir WITH NON-UNIQUE KEY object. 

SELECT * FROM tadir UP TO 1000000 ROWS INTO TABLE lt_tadir ORDER BY PRIMARY KEY. 

DATA(clas) = FILTER #( lt_tadir USING KEY primary_key WHERE object = 'CLAS' ). 
DATA(trans) = FILTER #( lt_tadir USING KEY primary_key WHERE object = 'TRAN' ).

我采用了@peterulb 为 1M 表准备的片段,这是我的测量结果:

0.032947、1000000、128776、0 过滤器
0.139579、1000000、128776、0 标准
0.239092、1000000、128776、0 sorted_secondary
0.242161、1000000、128776、0 sorted_secondary_val

尽管 FILTER 使用内联声明并将所有源字段传输到结果表中(这是设计使然),但它的执行速度比其他变体快得多。

我不坚持这将成为所有数据库的经验法则,但至少 HANADB 上的 ABAP 7.54 使用了一些针对 FILTER 语句的内置优化。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...