【问题标题】:Efficient Alternative to Outer Join外部联接的有效替代方案
【发布时间】:2009-04-23 21:47:38
【问题描述】:

此查询中的RIGHT JOIN 导致lims.operator 上的TABLE ACCESS FULL。常规连接运行很快,但当然不会显示示例“WHERE authorised_by IS NULL”。

在这种情况下,有没有比RIGHT JOIN 更有效的替代方法?

  SELECT   full_name
  FROM       (SELECT   operator_id AS authorised_by, full_name
                FROM lims.operator)
  RIGHT JOIN (SELECT   sample_id, authorised_by
                FROM   lims.sample
               WHERE   sample_template_id = 200)
  USING (authorised_by)

注意:显示的所有列(全名除外)都已编入索引,并且是某些表的主键。

【问题讨论】:

  • 你为什么要加入结果集而不是表?
  • 两个表都包含此查询不需要的列。
  • 然后不要将它们包含在 SELECT 子句中。它们在您的 JOIN 和 WHERE 子句中仍然有效。
  • 这些表中有多少行? sample_template_id = 200 有多少?

标签: oracle outer-join


【解决方案1】:

由于您正在执行外连接,因此执行全表扫描实际上可能比使用索引更有效。

如果您确信应该使用索引,请通过提示强制它:

SELECT /*+ INDEX (lims.operator operator_index_name)*/ ...

然后看看会发生什么......

【讨论】:

  • 我相信 lims.operator 只有 82 个条目。我插入了删除索引的 INDEX 提示,但是跟踪比较几乎相同。
  • 82 行相当于一个块。 Oracle确实做对了,通常:-)
【解决方案2】:

无需嵌套查询。试试这个:

select s.full_name
from lims.operator o, lims.sample s
where o.operator_id = s.authorised_by(+)
and s.sample_template_id = 200

【讨论】:

  • 此查询仍会导致 lims.operator 上出现“TABLE ACCESS FULL”。
  • 我再也不会使用这个 (+) 连接了,因为 oracle 有真正的 ansi 连接(我认为是从第 9 版开始)。 (+) 运算符并不总是有效(例如,您不能从 A 到 B 和从 B 到 C 的左外连接),但是 oracle 没有告诉这一点,而是默默地返回错误的结果。这是尴尬和不可预测的。我不喜欢它。
  • 那么你没有被 lims.operator 表上的 operator_id 索引。
  • 也这么想。你应该检查你的索引
  • @Stefan:注意点(这是我至少从 Oracle 8i 开始就使用的习惯),但如果您知道它的局限性,它就可以正常工作。我使用(和维护)的大部分代码都是这样编写的,所以我更熟悉。
【解决方案3】:

我有一段时间没有为 oracle 编写 sql,但我会这样编写查询:

SELECT lims.operator.full_name
FROM       lims.operator
RIGHT JOIN lims.sample
           on lims.operator.operator_id = lims.sample.authorized_by
           and sample_template_id = 200

这仍然表现得那么糟糕吗?

【讨论】:

  • 此查询导致 lims.operator 上的“表访问权限已满”。
  • +1:与我的基本相同,但使用“RIGHT JOIN”语法而不是 Oracle 的 (+) 语法。如果你也给表加上别名,可能更容易阅读。
  • @Steven,你检查过 lims.operator.authorized_by 上的索引吗?它只能是该字段的索引。
  • 它实际上是他正在使用的 operator 表上的 operator_id 列(您可能需要编辑您的答案以反映这一点),但如果需要,Oracle 可以使用复合索引(如果查询计划显示它是最佳选择)。
  • 谢谢,已修复。 @Steven 再次:您是否检查了 lims.operator.operator_id 上的索引?它必须是主键。我简直不敢相信它会对此执行全表扫描。
猜你喜欢
  • 1970-01-01
  • 2011-09-24
  • 2013-09-22
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多