【问题标题】:Load whole database table then filter in memory, or load only filtered entries?加载整个数据库表然后在内存中过滤,还是只加载过滤的条目?
【发布时间】:2020-12-25 19:05:49
【问题描述】:

我需要从数据库中编写一个客户搜索程序。

我知道数据库用于管理大量数据。但是我的“导师”告诉我尽可能少地与数据库交互。

将整个数据库表读入内部表,然后根据用户输入的参数进行过滤是否更好:

SELECT * FROM customer INTO TABLE it_customer.

LOOP AT it_customer INTO wa.
      WHERE .... IN ...
  APPEND wa TO output.
ENDLOOP.

还是直接访问数据库表?

SELECT * FROM customer 
      INTO wa
      WHERE ... in ...
  APPEND wa TO output.
ENDSELECT.

【问题讨论】:

  • 这个问题与ABAP无关,问题是哪个更快,数据库还是应用程序?也许这个question 的答案会对你有所帮助。
  • 坦率地说,这取决于您下面的数据库(尤其是 HANA)。根据您的数据库和要选择的数据量,有很多解决方案。

标签: database abap opensql


【解决方案1】:

确实,数据库访问被认为是一项昂贵的操作。 习惯以正确的方式访问 DB 绝对会提升您的系统性能。

通常,减少数据库访问次数是一个很好的起点。然而,在“正确的方式”等式中要考虑的不仅仅是它。

让我们来看看你的具体情况:

* A single DB access:
SELECT * 
  FROM customer
  INTO CORRESPONDING FIELDS OF TABLE @lt_customer. 

* Then some manipualtion.
* ...

陷阱:

  1. 从 DB 到应用服务器的数据流如前所述是昂贵的。不仅访问量是一个因素,数据量也是一个因素。如果不需要所有客户(例如客户个人信息屏幕),则将所有其他不需要的客户转移到应用程序服务器会产生很大的开销。
  2. 如果只选择一次,比如在您的流程开始时,选择整个表可能没问题。但是,在许多流程中,数据库会在流程中间发生更改(例如,如果它是所有客户的概览屏幕)。在这种情况下,您将不得不刷新数据并且使用另一个 select * 这样做可能是错误的。
  3. 数据库访问确实很昂贵,但内部操作也不是免费的。当N 是客户数据库表中的记录数时,执行select * 将在lt_customer 中给出N 行的开头。有时不可避免地会以n^2 甚至更多的顺序进行计算。随着 N 的增长,处理它所花费的时间也在增长。

我现在没时间了。当我有更多时间时,我会尝试扩展更多。祝你好运。

附: SELECT... ENDSELECT. 被认为是一种不好的做法。您可以在示例here 中了解它。

【讨论】:

    【解决方案2】:

    SAP 在其performance notes 中声明的主要原则是:

    尽量减少点击次数

    这意味着 WHERE 条件永远不应为空,就像您打算做的那样。您永远不应该阅读整个数据库。

    保持低读取次数原则仅在第三位,即在大量数据上不太重要。但是你也不应该滥用它,也不应该像你的第二个变体那样在循环中使用 DB 操作,除非你正在做一些特殊的事情。

    多说,您的代码违反了保持低数据量原则,因为您获取的是所有列而不是需要的列。除非你真的使用所有列,否则避免在 SELECT 中使用 *。

    所以答案是:使用第一段代码(但在 SELECT 中使用 WHERE!),这样会更有效率。在大多数情况下,ABAP 操作的成本低于 DB 操作。

    关于此主题的有用博客:

    https://blogs.sap.com/2014/05/21/a-complete-guide-to-opensql-statements-step-by-step-tutorial-with-screenshots/

    【讨论】:

      【解决方案3】:
      SELECT the, fields, you, really, need
        FROM customer
        INTO TABLE @DATA(customers)
        WHERE some_attribute = @some_value
          OR some_id IN @some_range.
      

      如果记录的数量很大,您可能需要处理包中的数据:

      SELECT the, fields, you, really, need
        FROM customer
        INTO TABLE @DATA(customers)
        WHERE some_attribute = @some_value
          OR some_id IN @some_range
        PACKAGE SIZE 1024.
      
        " some processing
      
      ENDSELECT
      
      • 一步读取尽可能多的记录,将昂贵的数据库往返次数降至最低。
      • 仅选择真正需要的列并使用 WHERE 来最大限度地减少内存占用和需要传输的数据量。

      【讨论】:

        【解决方案4】:

        使用 SELECT ... INTO TABLE

        当您获得更好的导师1时,将您的代码重构为合理的东西会容易得多。

        只有如果it_customer 导致内存转储,您应该使用 SELECT...ENDSELECT。


        1) 或 DBA 或 CTO,谁负责当前的,非常糟糕的政策

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-12-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-14
          • 1970-01-01
          • 2020-11-26
          • 2011-03-29
          相关资源
          最近更新 更多