【问题标题】:Oracle performance and join with OROracle 性能和加入 OR
【发布时间】:2020-10-08 19:39:59
【问题描述】:

我有时会遇到连接和“OR”子句的问题。例子简化了,但说明了问题的意思:

select a.ID, b.ID
from table a
  left join table2 b on (a.ID = b.ID)

结果:20k 行和 0.2 秒

select a.ID, b.ID
from table a
  left join table2 b on (a.ID2 = b.ID2)

结果:20k 行和 0.2 秒

select a.ID, b.ID
from table a
  left join table2 b on (a.ID = b.ID or a.ID2 = b.ID2)

结果:20k 行,时间为 30 秒!

平台:Oracle 11xe linux。

为什么执行时间会有这样的差异?

【问题讨论】:

  • 您的查询一开始就不是有效的 SQL。你在哪里定义b
  • "b" 是 table2 的别名
  • 请在代码问题中给出minimal reproducible example--包括剪切、粘贴和可运行的最小代码和以代码形式给出的最小代表性数据。对于包含 DBMS 和 DDL 的 SQL,包括约束、索引和表格初始化。对于包括 EXPLAIN 结果和统计信息的 SQL 性能。请研究和总结。对于包括优化/性能基础的 SQL——立即导致索引、计划、统计和 SARGability。 Tips for asking a good SQL question 在您学习并应用了这些基础知识后,请重新优化。 How to Ask
  • 请通过编辑而不是 cmets 澄清。

标签: oracle performance join


【解决方案1】:

scaisEdge 的回答提供了一个具体的解决方案,但也值得了解连接中的 OR 条件会导致性能问题的一般原因 - OR 条件会阻止优化器使用哈希连接。

散列连接通常是连接大量数据的最快方法。 (您的表可能很小,但由于没有过滤器,它们正在处理大部分数据。)但是哈希连接只能在相等条件下工作。要处理OR 条件,Oracle 将不得不使用较慢的连接方法,例如排序合并或嵌套循环。

如果您将两个表的行数视为MN,则哈希联接(理论上)可以在M+N 操作中完成,而排序合并联接可以在@987654328 中完成@。如果您好奇,this sample chapter 包含有关 Oracle 不同联接类型及其性能比较的更多详细信息。

UNION 版本必须连接表两次,但两次快速连接比一次慢速连接要好。 Oracle 不能总是将OR 转换为UNIONUNION ALL,因为这两个版本可能不一定返回与您的其他查询相同的行。例如,UNION 备选方案会以不同方式处理重复行。 (但也许您对您的数据了解一些 Oracle 不了解的信息,因此查询可能仍然适合您。)

这个知识很有用,因为OR 本身并不慢,我们并不总是想避免它。如果OR 只是索引访问的一部分,或者无论如何都不会使用哈希连接的连接的一部分,那么它没有任何问题。

【讨论】:

    【解决方案2】:

    代替 OR 尝试使用 UNION

    select a.ID, b.ID
    from tablea a
    left join tableb b a.ID = b.ID
    UNION 
    select a.ID, b.ID
    from tablea a
    left tableb b join a.ID2 = b.ID2
    

    或联合所有

    select a.ID, b.ID
    from tablea a
    left join tableb b a.ID = b.ID
    UNION  ALL
    select a.ID, b.ID
    from tablea a
    left tableb b join a.ID2 = b.ID2
    

    【讨论】:

    • 我不能使用 uni,因为这是一个由表之间的 30 个连接组成的查询... ;) 只有这个连接会导致这样的延迟。但我会尝试将这个调用(LEFT JOIN)分成两部分..
    • 嗯,选择a.ID, b.ID from table a left join table2 b on(b.id = a.id) left join table2 c on(c.id2 = a.id2) work很好!
    【解决方案3】:

    如果没有执行计划,真的不可能回答这样的性能问题。如果我不得不猜测,我怀疑您在 a.id 和 b.id 上有索引,但在 a.id2 和 b.id2 上没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-12
      • 2012-01-03
      • 1970-01-01
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多