【问题标题】:how do I speed up substr searches in my query如何加快查询中的 substr 搜索
【发布时间】:2012-05-01 09:46:30
【问题描述】:

我将其用作子选择(在连接其他 2 个表的简单查询中),您可以想象它需要一段时间才能运行。到目前为止,持续了 6 小时以上。 这是唯一的方法吗?我知道做另一个 JOIN 而不是子选择可能会有所帮助。但主要瓶颈是所有这些 OR 和子字符串。

SELECT ex_array
FROM   service_x 
WHERE  
   ( substr(ex_array,1,2) = 'FW' OR substr(ex_array,3,2) = 'FW' OR substr(ex_array,5,2) = 'FW' OR substr(ex_array,7,2) = 'FW' OR substr(ex_array,9,2) = 'FW' OR substr(ex_array,11,2) = 'FW' ) 
OR ( substr(ex_array,1,2) = 'IL' OR substr(ex_array,3,2) = 'IL' OR substr(ex_array,5,2) = 'IL' OR substr(ex_array,7,2) = 'IL' OR substr(ex_array,9,2) = 'IL' OR substr(ex_array,11,2) = 'IL' )  
OR ( substr(ex_array,1,2) = 'IN' OR substr(ex_array,3,2) = 'IN' OR substr(ex_array,5,2) = 'IN' OR substr(ex_array,7,2) = 'IN' OR substr(ex_array,9,2) = 'IN' OR substr(ex_array,11,2) = 'IN' )  
OR ( substr(ex_array,1,2) = 'IK' OR substr(ex_array,3,2) = 'IK' OR substr(ex_array,5,2) = 'IK' OR substr(ex_array,7,2) = 'IK' OR substr(ex_array,9,2) = 'IK' OR substr(ex_array,11,2) = 'IK' )  
OR ( substr(ex_array,1,2) = 'IH' OR substr(ex_array,3,2) = 'IH' OR substr(ex_array,5,2) = 'IH' OR substr(ex_array,7,2) = 'IH' OR substr(ex_array,9,2) = 'IH' OR substr(ex_array,11,2) = 'IH' )  
OR ( substr(ex_array,1,2) = 'KP' OR substr(ex_array,3,2) = 'KP' OR substr(ex_array,5,2) = 'KP' OR substr(ex_array,7,2) = 'KP' OR substr(ex_array,9,2) = 'KP' OR substr(ex_array,11,2) = 'KP' )  
)

【问题讨论】:

  • 您是否有查询的解释计划(查看 dbms_xplan 以获得此计划)?我希望查询可以通过全表扫描得到满足,因为您已经通过将函数应用于 ex_array 来使用任何标准索引停止数据库。 @dcp 建议的六个基于函数的索引可能会有所帮助。 service_x 有多少行,您希望查询返回多少行?您可能需要重新评估您的整体算法/设计以获得所需的性能。不过,关键可能是启用索引访问,具体取决于查询的选择性。
  • 大约 1220 万行(在 service_x 中),我应该得到大约 175,000 个结果。
  • 鉴于查询的高选择性 - 我建议如果您无法调整整个算法,您最好的选择是修改查询以通过对 ex_array 的索引访问来启用有效的行过滤器。我将在下面发布一个可能会有所帮助的答案。

标签: oracle substr substring


【解决方案1】:

您可以尝试使用function based index。具体来说,在 substr(ex_array,3,2) 和 substr(ex_array,9,2) 等上创建基于函数的索引。

不过,它可能有很多索引,因此您必须通过运行一些测试来衡量它的帮助程度。但这是一个开始的想法。

我假设您使用的是 8i 或更高版本。

【讨论】:

    【解决方案2】:

    这个结构怎么样...

    INSTR( ex_array, 'FW' ) IN (1,3,5,7,9,11)
    

    那么至少你只会做一次字符串解析...

    【讨论】:

    • 这个方法其实是目前为止使用正则表达式最快的方法,按我的方式做,按我的方式做。
    • @mathewbutler 我上面的方法需要 183.33 秒 正则表达式需要 511.89 秒 INSTR+IN 方法需要 155.46 秒
    • 是的,但是一旦有了索引,您就会看到真正的改进。检查后(他们)...
    • 同意,基于函数的索引应该对所有 3 个都有帮助
    • 我不认为这在语义上与最初发布的查询相同。它只检查一种情况。
    【解决方案3】:

    也许regexp_like

    REGEXP_LIKE(ex_array, '^(.{2}){0,5}(FW|IL|IN|IK|IH|KP).*$')
    

    (正则表达式可能写得更好……)

    您还可以按照 dcp 的建议添加基于函数的索引(尽管您只需要一个):

    create index fbIndex on service_x (REGEXP_INSTR(ex_array, '^(.{2}){0,5}(FW|IL|IN|IK|IH|KP).*$'));
    

    以及更改要使用的查询:

    REGEXP_INSTR(ex_array, '^(.{2}){0,5}(FW|IL|IN|IK|IH|KP).*$') = 1
    

    【讨论】:

    • 这很好,但正如@mathewbutler 所说 - 真正的改进将是有索引时
    • 请注意您正在比较具有相同功能的查询。查询计划对于比较查询的两个运行时行为很有价值。
    【解决方案4】:

    鉴于我建议的可用信息,以及您需要的查询的选择性:

    1) ex_array 上的索引(最好只是 ex_array,或者 ex_array 在索引的前沿。

    2) 修改查询。如果您附加其他过滤条件:

    ... 和 (Ex_array like '%FW%' OR ex_array like '%IL%' or ex_aray like .... 等涵盖了六种情况中的每一种。有了索引,这应该能够进行索引范围扫描以减少 1220 万仅包含您感兴趣的六个字符串之一的行。只有这些行才会应用您的 substr 逻辑,留下预期的 175K。

    原则上这应该会提高效率。不过,它确实很大程度上取决于数据分布(例如,所有 1200 万行都可能包含六个字符串之一,只是不在原始查询中指定的位置。在这种情况下,我建议的更改可能比原始的效率低询问)。可能还有其他选择,但我需要更多信息,包括更准确地解释计划。

    希望这会有所帮助 - 祝你好运!!

    【讨论】:

    • 哦,太好了。整个事情变得更加复杂。任何一个关系(到另一个表)都可以有多行数据。如果多行中的任何一行包含这些值中的一个,我实际上需要提取所有数据/行(最多 5 个额外行)。 (不仅仅是具有找到值的行)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    • 1970-01-01
    • 2011-12-14
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多