甲骨文性能并与 OR 联接



我有时对连接和"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。

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

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

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

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

UNION版本必须联接表两次,但两个快速联接可能比一个慢联接更好。Oracle 不能始终将OR转换为UNIONUNION ALL,因为这两个版本不一定返回与其他查询相同的行。例如,UNION替代项将区别对待重复行。(但也许您知道一些 Oracle 不知道的数据,因此查询可能仍然适合您。

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

而不是 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

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

最新更新