【问题标题】:SQL query optimizerSQL 查询优化器
【发布时间】:2015-02-03 01:33:34
【问题描述】:

我什么都听不懂。我有包含大量数据和表的 Oracle 11g 数据库。我想加入一些表格并输出它的结果。 好的,刚刚写了:

SELECT *
FROM Table1
LEFT JOIN Table2 ON Table2.Table1_Id = Table1.Table1_Id
WHERE Table2.Column1=1
  • 非常简单,但是太慢了。 好的,Table2 与 Table3 连接。该表在列中包含一些标志,可以告诉我们它通常与 Table1 连接。 我写了下一段代码:

    SELECT *
    FROM Table1
    LEFT JOIN Table2 ON Table2.Table1_Id = Table1.Table1_Id
    LEFT JOIN Table3 ON Table3.Table3_Id = Table2_Table3_Id
    WHERE
    Table3.ColumnWithFlag LIKE '%some id info about Table1%'
    AND Table2.Column1=1
    

而且这个查询比第一次查询成本低,速度快。为什么,我无法理解?我在查询中使用了 3 个表,它的工作速度更快,然后使用 2 个表进行查询(行数相同,数据相同)。

【问题讨论】:

  • OUTER JOIN时,不要将外表的条件放在WHERE子句中,而是放在ON子句中。 (否则会执行常规的内部连接。)
  • @jarlh,外连接时,ON 子句和 Where 子句中的谓词本质上是不同的。你应该非常小心,不要得到不正确的结果。它会在哪里过滤行,而在 ON 时它不会
  • 第二个查询中有一个附加条件,Table3.ColumnWithFlag LIKE '%some id info about Table1%' 我假设它会过滤结果集中的大部分数据,但这仍然是文本解析,LIKE 在做这个操作。但这只是猜测。最好比较两个查询的执行计划,看看“瓶颈”在哪里。
  • @GiorgiNakeuri,是的,这是不同的。但是在这种特定情况下,where 子句条件是否不会使外连接返回与内连接相同的结果?
  • @jarlh, nope... 在内部联接中,您可以在 ON 子句中编写谓词,或将它们移动到 where 子句。在外连接中,如果你有 where some = 1 它将过滤连接结果,如果你将 where 移到 ON 它不会过滤,它将返回所有行,但在条件不成立的地方放置 NULL

标签: sql oracle optimization


【解决方案1】:

首先,一些基础知识。这是您的第一个查询:

SELECT *
FROM Table1 t1 LEFT JOIN
     Table2 t2 
     ON t2.Table1_Id = t1.Table1_Id
WHERE t2.Column1 = 1;

LEFT JOIN 是不必要的,因为WHERE 子句无论如何都会把它变成INNER JOIN。如果没有匹配,那么t2.Column1 就是NULL,它会被过滤掉。

我可以想象至少有一种方式可以让您看到这个性能问题。基本上,如果Table2Table1_Id 上没有索引,但在Table3_Id 上确实有索引。

在这种情况下,第一个查询计划需要扫描Table2(可能使用Column1 上的索引),然后执行数据库魔术——可能是对表进行哈希连接。

第二个查询将使用可用索引连接Table2Table3。这将(大概)比Table2 小得多。数据库魔法可以避免对一个非常大的表进行全表扫描。

这是一种可能的情况。真正的方法是查看查询的执行计划,看看有什么不同。

【讨论】:

  • 我也这么认为,但我无法理解“Oracle 是如何理解的,他应该从 Table2 中‘删除’不需要的行”。
  • @Mixim 。 . .这是如何在查询中访问行的问题。第一个查询可能只给 Oracle 一种访问它们的方法——扫描表中的所有行。第二个可能会为 Oracle 提供另一种使用索引的访问方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 2014-02-04
  • 2014-11-16
  • 2011-06-22
  • 2015-08-10
相关资源
最近更新 更多