哪个具有更好的性能:SELECT ... ENDSELECT(1乘1)或SELECT ... INTO TABLE / LOOP AT

eke*_*kos 2 sap abap

我必须从表中读取10.000.000条记录。

是不是更好:

  • 使用SELECT ... ENDSELECT(没有内部表)一一读取这些记录
  • 还是使用一次读取所有它们,SELECT ... INTO TABLE itab然后通过此内部表进行遍历?

Flo*_*ian 5

如果所有10,000,000个条目都适合ABAP的主内存,则应选择所有单个条目SELECT ... INTO TABLE ...,然后选择一个LOOP

这样可以将昂贵的数据库交互减少到最低程度,并且将是最快的。

如果记录不适合主存储器,则需要在包中检索它们。检查PACKAGE SIZESELECT语句的附加内容。

  • 数据是否适合的问题对于所有选择均有效,但大多数操作都是一步完成,而不是打包完成。我们通常会估计记录数和大小,并根据假定的系统设置(尤其是主内存)对其进行验证,以决定是否添加包装。但是您说的没错,〜10M选择肯定是“为了安全起见,让我们添加包装……”的不错选择。比单列GUID列表宽的任何内容都可能会耗尽内存。:-) (2认同)

And*_*rás 5

他们的速度差不多

流行的看法相反,SELECT ... ENDSELECT没有一个接一个获取行,因此它的性能是不是太多有过之而无不及SELECT ... INTO TABLE。请参阅此处说明

最大的问题SELECT ... ENDSELECT是它阻止了其他性能改进

考虑这个编码:

SELECT matnr FROM mara
    INTO lv_matnr WHERE (...).
  SELECT SINGLE ebeln
      FROM ekpo 
      INTO lv_ebeln 
      WHERE matnr = lv_matnr.
  SELECT SINGLE zfield
      FROM ztable 
      INTO lv_zfield 
      WHERE matnr = lv_matnr.
  ...
ENDSELECT.
Run Code Online (Sandbox Code Playgroud)

大部分时间都花在表ekpo和SELECT SINGLE 上ztable,通常解决方案是使用FOR ALL ENTRIES1,但是您需要一个内部表。
所以SELECT ... INTO TABLE无论如何它必须转换为:

SELECT matnr FROM mara
    INTO TABLE lt_matnr WHERE (...).
IF lt_mara IS NOT INITIAL.
  SELECT matnr, ebeln FROM ekpo
      INTO TABLE @lt_ekpo          "make it SORTED by matnr"
      FOR ALL ENTRIES IN @lt_matnr
      WHERE matnr = @table_line.
  SELECT matnr, zfield FROM ztable
      INTO TABLE @lt_ztable        "make it SORTED by matnr"
      FOR ALL ENTRIES IN @lt_matnr
      WHERE matnr = @table_line.
ENDIF. 
LOOP AT lt_matnr ASSIGNING <fs_mara>.
  READ TABLE lt_ekpo ASSIGNING <fs_ekpo>
      WITH KEY matnr = <fs_matnr>.
  READ TABLE lt_ztable ASSIGNING <fs_ztable>
      WITH KEY matnr = <fs_matnr>.
  ...
ENDLOOP.
Run Code Online (Sandbox Code Playgroud)

应该避免SELECT ... ENDSELECT,不是因为它本身的性能,而是为了使其他改进更容易。


  1. 你应该尽可能使用 JOINs 而不是 FOR ALL ENTRIES