使用 7.40+ 语法针对另一个 itab 值过滤 itab 的高效方法?
Performant way to filter itab against another itab values with 7.40+ syntax?
假设我有 2 个内部表:
TYPES:BEGIN OF LTY_FILE,
SOKEY TYPE CHAR5,
SOPONO TYPE CHAR15,
SOCONO TYPE CHAR15,
FLAG TYPE C,
END OF LTY_FILE.
data:IT_ARCHIVE TYPE TABLE OF LTY_FILE,
IT_SAP TYPE TABLE OF LTY_FILE.
it_archive = VALUE #(
( sokey = 'Key1' sopono = 'PO#12' socono = 'Three' flag = 'A' )
( sokey = 'Key2' sopono = 'PO#34' socono = 'Four' flag = 'B' ) ).
it_sap = VALUE #(
( sokey = 'Key1' sopono = 'PO#12' socono = 'Three' flag = 'A' ) ).
IT_ARCHIVE
:
SOKEY
索波诺
索科诺
旗帜
Key1
PO#12
三个
一个
键2
PO#34
四个
B
IT_SAP
:
SOKEY
索波诺
索科诺
旗帜
Key1
PO#12
三个
一个
现在我想要 IT_ARCHIVE
中不存在于 IT_SAP
中的行,基于键 SOKEY
、SOPONO
和 SOCONO
,以使用 FLAG = D
:
添加到 IT_SAP
SOKEY
索波诺
索科诺
旗帜
键2
PO#34
四个
B
所以,新的 IT_SAP
应该是这样的:
SOKEY
索波诺
索科诺
旗帜
Key1
PO#12
三个
一个
键2
PO#34
四个
D
到目前为止,我尝试了以下方法,但在 ABAP 7.4 中失败了,但由于数据非常庞大(每个 运行 超过 400K),我正在寻找以性能为中心的代码来实现这一点.
DATA(ls_wa) = it_sap[ 1 ]. " Temporary workarea for insertion.
CLEAR:ls_wa
LOOP AT IT_ARCHIVE ASSIGNING FIELD SYMBOL(<lfs_archive>).
IF NOT LINE_EXISTS( it_sap[ sokey = <lfs_Archive>-sokey
sopono = <lfs_Archive>-sopono
socono = <lfs_archive>-socono ] ).
ls_wa = <lfs_archive>.
ls_wa-flag = 'D'.
APPEND ls_wa to IT_SAP.
CLEAR:ls_wa.
ENDIF.
ENDLOOP.
我尝试的第二种方法:
data(LT_FINAL) = IT_SAP[].
REFRESH:LT_FINAL[].
lt_final = VALUE #( FOR ls_ar IN IT_ARCHIVE
FOR ls_sap IN IT_SAP WHERE ( sokey <> <lfs_Archive>-sokey
sopono <> <lfs_Archive>-sopono
socono <> <lfs_archive>-socono )
(
"Explicitly mentioning all fields as have to change FLAG value
sokey = ls_Ar-sokey
sopono = ls_ar-sopono
socono = ls_ar-socono
flag = 'D'
) ).
第一种方法,数据量大,耗时长。令我惊讶的是,第二种方法并没有给我与第一种方法相同的结果。
在 ABAP 7.4+ 中有没有更好的方法来实现这一点?
您的主要问题是关于性能的。有关信息,Stack Overflow 中还有其他类似的 questions/answers 涉及性能和内部 tables。
在您的情况下,您使用“标准”table 类型 (DATA ... TYPE TABLE OF ...
),因此每次查找 (line_exists
) 都会查看内部 table 直到找到一个。与其一遍又一遍地查看所有行,不如内部table排序一次,每次查找会快很多;这很容易理解为什么:如果你,人类,看字典(书)中的一个词,希望这些词被排序并且你会很快找到这个词(前提是你知道字母 A,B,C 等的顺序.; 电脑也一样
内部排序有两种方式table:
- 隐含地,通过将其声明为“排序”或“散列”内部 table 并且内部 table 的任何初始化或更改将自动更新索引。
- 或明确地,通过语句
SORT
。此选项更易于理解,但尽可能不推荐使用。
要在排序和散列(即隐式排序)之间进行选择,您必须简单地知道是否可能有两个相同的行具有完全相同的键。
- 如果是,您必须选择 排序 内部 table 和 非唯一 键。
- 如果不是,您可以选择 hashed 内部 table,根据定义,它使用 unique 密钥。
有关详细信息,请阅读 ABAP documentation - itab - Selection of the Table Category.
在你的例子中,只要做下面的声明就会显着提高你当前(工作)算法的性能:
TYPES:BEGIN OF lty_file,
sokey TYPE char5,
sopono TYPE char15,
socono TYPE char15,
flag TYPE c,
END OF lty_file.
TYPES:lty_file_tab TYPE SORTED TABLE OF lty_file WITH NON-UNIQUE KEY sokey sopono socono.
DATA:it_archive TYPE lty_file_tab,
it_sap TYPE lty_file_tab.
您还可以通过使用内置运算符 FILTER
稍微改进您的算法,我认为它在内核中运行得更多(有关 FILTER
的更多信息,请参见其他 ).
例如:
it_sap = VALUE #(
BASE it_sap
( LINES OF VALUE #( FOR <line> IN
FILTER #( it_archive EXCEPT IN it_sap
WHERE sokey = sokey
AND sopono = sopono
AND socono = socono )
( VALUE #( BASE <line> flag = 'D' ) ) ) ) ).
ASSERT it_sap = VALUE lty_file_tab(
( sokey = 'Key1' sopono = 'PO#12' socono = 'Three' flag = 'A' )
( sokey = 'Key2' sopono = 'PO#34' socono = 'Four' flag = 'D' ) ).
(注意:我在这里使用 ASSERT
只是为了证明内部 table 具有指定的值;否则会停止 program/raise 运行时错误)
假设我有 2 个内部表:
TYPES:BEGIN OF LTY_FILE,
SOKEY TYPE CHAR5,
SOPONO TYPE CHAR15,
SOCONO TYPE CHAR15,
FLAG TYPE C,
END OF LTY_FILE.
data:IT_ARCHIVE TYPE TABLE OF LTY_FILE,
IT_SAP TYPE TABLE OF LTY_FILE.
it_archive = VALUE #(
( sokey = 'Key1' sopono = 'PO#12' socono = 'Three' flag = 'A' )
( sokey = 'Key2' sopono = 'PO#34' socono = 'Four' flag = 'B' ) ).
it_sap = VALUE #(
( sokey = 'Key1' sopono = 'PO#12' socono = 'Three' flag = 'A' ) ).
IT_ARCHIVE
:
SOKEY | 索波诺 | 索科诺 | 旗帜 |
---|---|---|---|
Key1 | PO#12 | 三个 | 一个 |
键2 | PO#34 | 四个 | B |
IT_SAP
:
SOKEY | 索波诺 | 索科诺 | 旗帜 |
---|---|---|---|
Key1 | PO#12 | 三个 | 一个 |
现在我想要 IT_ARCHIVE
中不存在于 IT_SAP
中的行,基于键 SOKEY
、SOPONO
和 SOCONO
,以使用 FLAG = D
:
IT_SAP
SOKEY | 索波诺 | 索科诺 | 旗帜 |
---|---|---|---|
键2 | PO#34 | 四个 | B |
所以,新的 IT_SAP
应该是这样的:
SOKEY | 索波诺 | 索科诺 | 旗帜 |
---|---|---|---|
Key1 | PO#12 | 三个 | 一个 |
键2 | PO#34 | 四个 | D |
到目前为止,我尝试了以下方法,但在 ABAP 7.4 中失败了,但由于数据非常庞大(每个 运行 超过 400K),我正在寻找以性能为中心的代码来实现这一点.
DATA(ls_wa) = it_sap[ 1 ]. " Temporary workarea for insertion.
CLEAR:ls_wa
LOOP AT IT_ARCHIVE ASSIGNING FIELD SYMBOL(<lfs_archive>).
IF NOT LINE_EXISTS( it_sap[ sokey = <lfs_Archive>-sokey
sopono = <lfs_Archive>-sopono
socono = <lfs_archive>-socono ] ).
ls_wa = <lfs_archive>.
ls_wa-flag = 'D'.
APPEND ls_wa to IT_SAP.
CLEAR:ls_wa.
ENDIF.
ENDLOOP.
我尝试的第二种方法:
data(LT_FINAL) = IT_SAP[].
REFRESH:LT_FINAL[].
lt_final = VALUE #( FOR ls_ar IN IT_ARCHIVE
FOR ls_sap IN IT_SAP WHERE ( sokey <> <lfs_Archive>-sokey
sopono <> <lfs_Archive>-sopono
socono <> <lfs_archive>-socono )
(
"Explicitly mentioning all fields as have to change FLAG value
sokey = ls_Ar-sokey
sopono = ls_ar-sopono
socono = ls_ar-socono
flag = 'D'
) ).
第一种方法,数据量大,耗时长。令我惊讶的是,第二种方法并没有给我与第一种方法相同的结果。
在 ABAP 7.4+ 中有没有更好的方法来实现这一点?
您的主要问题是关于性能的。有关信息,Stack Overflow 中还有其他类似的 questions/answers 涉及性能和内部 tables。
在您的情况下,您使用“标准”table 类型 (DATA ... TYPE TABLE OF ...
),因此每次查找 (line_exists
) 都会查看内部 table 直到找到一个。与其一遍又一遍地查看所有行,不如内部table排序一次,每次查找会快很多;这很容易理解为什么:如果你,人类,看字典(书)中的一个词,希望这些词被排序并且你会很快找到这个词(前提是你知道字母 A,B,C 等的顺序.; 电脑也一样
内部排序有两种方式table:
- 隐含地,通过将其声明为“排序”或“散列”内部 table 并且内部 table 的任何初始化或更改将自动更新索引。
- 或明确地,通过语句
SORT
。此选项更易于理解,但尽可能不推荐使用。
要在排序和散列(即隐式排序)之间进行选择,您必须简单地知道是否可能有两个相同的行具有完全相同的键。
- 如果是,您必须选择 排序 内部 table 和 非唯一 键。
- 如果不是,您可以选择 hashed 内部 table,根据定义,它使用 unique 密钥。 有关详细信息,请阅读 ABAP documentation - itab - Selection of the Table Category.
在你的例子中,只要做下面的声明就会显着提高你当前(工作)算法的性能:
TYPES:BEGIN OF lty_file,
sokey TYPE char5,
sopono TYPE char15,
socono TYPE char15,
flag TYPE c,
END OF lty_file.
TYPES:lty_file_tab TYPE SORTED TABLE OF lty_file WITH NON-UNIQUE KEY sokey sopono socono.
DATA:it_archive TYPE lty_file_tab,
it_sap TYPE lty_file_tab.
您还可以通过使用内置运算符 FILTER
稍微改进您的算法,我认为它在内核中运行得更多(有关 FILTER
的更多信息,请参见其他
例如:
it_sap = VALUE #(
BASE it_sap
( LINES OF VALUE #( FOR <line> IN
FILTER #( it_archive EXCEPT IN it_sap
WHERE sokey = sokey
AND sopono = sopono
AND socono = socono )
( VALUE #( BASE <line> flag = 'D' ) ) ) ) ).
ASSERT it_sap = VALUE lty_file_tab(
( sokey = 'Key1' sopono = 'PO#12' socono = 'Three' flag = 'A' )
( sokey = 'Key2' sopono = 'PO#34' socono = 'Four' flag = 'D' ) ).
(注意:我在这里使用 ASSERT
只是为了证明内部 table 具有指定的值;否则会停止 program/raise 运行时错误)