【问题标题】:Performance when using wildcard % in Select LIKE在 Select LIKE 中使用通配符 % 时的性能
【发布时间】:2013-11-01 00:32:50
【问题描述】:

我有以下非常缓慢且低效的语句,我想选择 e071 中的所有条目,其中 obj_name 字段包含 tadir 中的 obj_name 字段的值,后跟通配符。

LOOP AT tadir ASSIGNING <fs_tadir>.

   CONCATENATE <fs_tadir>-obj_name '%' INTO gv_obj_name.

    SELECT * FROM e071 APPENDING TABLE gt_e071 
       WHERE obj_name LIKE gv_obj_name.

ENDLOOP.

由于不能将 LIKE 语句与“For all entries in”或连接一起使用,有什么方法可以提高效率?

【问题讨论】:

  • 根据表 TADIR 和 E071 中有多少条目,从 E071 中选择所有条目,然后删除不需要的条目可能更有效。除非您确实需要所有字段,否则请尽量不要使用 select *。您可以使用事务 SAT 来衡量每个事务的性能。请记住,缓冲可能会影响任何后续运行,因此请确保您不要总是先运行一个测试,而是将它们混合起来以获得更好的结果。
  • 有很多字段... Select * 是否比按名称选择字段更快(假设 RAM 不是限制因素),因为您不需要查找要返回的列?
  • 是的,如果您需要大部分字段,SELECT * 可能会更快,并且更容易维护。您总是在减少数据库负载与减少网络负载和保持代码可维护性之间保持平衡。
  • 您可以通过使用重复的通配符选择与 TADIR 建立一个包含您需要的所有对象名称的内部表。然后您可以使用此表对 E071 执行 FOR ALL ENTRIES 选择。这应该会更快,因为 TADIR 每个对象只有一次,而 E071 可以多次。

标签: performance abap opensql


【解决方案1】:

LIKE 对数据库来说是非常可怕的,因为你在一个循环中有这个,你很可能在每次循环迭代中扫描整个 E071。您应该尝试交换它并选择 E071 中的所有内容,然后在 SELECT...ENDSELECT 中检查您的表。我知道这听起来有悖常理,但它在我们构建的自定义 REGUH 索引上救了我。

SELECT * FROM e071 APPENDING TABLE gt_e071 
   WHERE obj_name LIKE gv_obj_name.

  READ TABLE tadir WITH KEY.... ASSIGNING <fs_tadir>.

ENDSELECT.

作为替代选择,而不是使用单个 like 构建一系列值并将它们批量发送到选择。它的性能仍然会很差,但会更好。

data lt_obj_range type range of e071-obj_name.
data ls_obj_range like line of lt_obj_range.

LOOP AT tadir ASSIGNING <fs_tadir>.
   ls_obj_range-sign = 'I'.
   ls_obj_range-option = 'CP'.
   CONCATENATE <fs_tadir>-obj_name '*' INTO ls_obj_range-low.
   append ls_obj_range to lt_obj_range.

endloop.

SELECT * FROM e071 APPENDING TABLE gt_e071 
       WHERE obj_name it lt_obj_range.

请注意,数据库对 select 语句的大小有限制,因此如果您的范围内有太多项目,您将得到一个简短的转储,因此请将其分解为大约 200-300 行的范围。

【讨论】:

    【解决方案2】:

    使用 SQL 跟踪(事务ST05)来分析您的查询。主要问题之一 - 除了您可能在数据库中引发数千个查询这一事实之外 - 将是您根本没有使用任何索引,甚至没有执行范围扫描。这可能会迫使 DBMS 执行数千次全表扫描。如果您提供PGMIDOBJECT,它应该会大大加快速度。

    使用前缀来限制您正在查看的传输请求的数量可能也是一个好主意。我刚刚检查了我们的几个系统 - 根据系统的年龄,E071 中的一半条目根本不属于传输。在一个系统中,本地创建了超过 450 万个条目中的 75,000 个条目,其他的是支持包等的片断列表。

    From an earlier question,我知道你想要达到的目标。请注意,您不能依赖主要对象名称位于部分对象名称的开头。您可能需要检查功能模块 TR_CHECK_TYPE 的编码,以了解部分 (LIMU) 条目如何映射到整个对象条目 (R3TR)。但是,我不知道有什么功能模块可以反方向工作。

    在这个阶段我不会担心选择单个字段而不是SELECT *。与您在其他响应或 cmets 中可能读到的相反,E071 是一个相对狭窄的表,字段很少,并且您已经需要查询中的最大字段。仅选择单个字段可能没有什么好处。

    【讨论】:

    • 这个循环和选择语句专门用于类方法对象 - 在我们的系统中,至少这种模式似乎适用于那种情况 - 虽然通过前缀限制听起来是个好主意
    • 您应该在查询 TADIR 时担心 SELECT *,因为这是一个宽表。此外,在列存储架构中,您应该始终担心它。
    • @hennes:如果你仔细阅读这个问题,你会注意到他不是在查询 TADIR,而是在查询 E071。
    • 我知道,但我认为在某些时候他必须填充他循环的内部表 tadir。
    猜你喜欢
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 2011-09-07
    • 2012-02-22
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多