问题描述
我正在尝试为以下场景编写一个 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 AT
和 CASE
语句组合,迭代次数将与 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_augru
和 ranges-t_vkorg
而不是 t_augru
和 t_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 语句的内置优化。