【问题标题】:Why is my SQL request much slower when the condition is in the join?当条件在连接中时,为什么我的 SQL 请求要慢得多?
【发布时间】:2015-09-14 14:19:42
【问题描述】:

我有一个包含以下列的表格:

  1. 身份证
  2. 主ID

主 ID 可以在具有不同 ID 的不同行之间共享。

例如:

ID | Master ID
1  |  1
2  |  1
3  |  1
4  |  2

知道 ID 我想检索所有共享相同主 ID 的行

我设法用这个查询做到了:

Select * 
FROM table t
LEFT JOIN table t2
ON t.MASTER_ID = t2.MASTER_ID 
Where t.ID = '1'

然后我也尝试使用:

Select * 
FROM table t
LEFT JOIN table t2
ON t.MASTER_ID = t2.MASTER_ID and t.ID = '1'

在那种情况下,它要慢得多。谁能解释一下为什么?

【问题讨论】:

  • 哪个 dbms? (不同的产品优化不同...)
  • 缓存/磁盘问题?比较执行计划?
  • 看查询计划
  • 它们返回的数据集是否完全相同?
  • @JoePhilllips :第二个请求实际上失败了(我为该查询使用了太多资源......)但我现在得到了解释。

标签: sql oracle join left-join


【解决方案1】:

查询在做不同的事情,首先是你说的:

1. give me all rows from `table` where `id = 1`
2. Also give me rows from t2 with a matching master ID

你说的那一秒

1. Give me all rows from `table`
2. Return rows from `t2` with a matching master ID and where `t1.ID = 1`

举个简单的例子

ID  Master_ID
------------------------
1   1
2   1
3   1
4   2

所以你的第一个查询将返回:

t1.ID   t1.Master_ID    t2.ID   t2.Master_ID
--------------------------------------------
1           1           1       1
1           1           2       1
1           1           3       1

您的第二个查询将返回

t1.ID   t1.Master_ID    t2.ID   t2.Master_ID
--------------------------------------------
1           1           1       1
1           1           2       1
1           1           3       1
2           1           NULL    NULL
3           1           NULL    NULL
4           2           NULL    NULL

所以基本上在第一个查询中,您从表中返回有限数量的行,而在第二个查询中,您返回所有行,但只连接其中的一些。

【讨论】:

  • 好收获:-)。我假设ONWHERE 子句之间的这种差异仅在有OUTER 连接时才会出现。对于INNER 连接,谓词可以是ONWHERE。那正确吗?一个sqlfiddle会很好。谢谢。
  • 没错,使用内连接,两个查询是等价的。 sqlfiddle.com/#!4/9bf52/1
  • 感谢您的解释!所以基本上 Where 子句适用于选择的第一个表,而不适用于连接的结果,对吧?我想我错过了这个细节......
  • 本页说明:stackoverflow.com/questions/1018822/… 说得更清楚了!
【解决方案2】:

如果 t.ID = '1' 条件在 WHERE 子句中,则只需针对 t 中的行数评估 t.ID='1' 条件。如果将t.ID='1' 条件放入连接的ON 子句中,则必须对t2 中的所有行进行评估。如果 t2 中有很多行,这会显着增加查询的运行时间。

【讨论】:

  • 当然,但是将条件放在join on ...意味着条件将在join匹配操作后进行评估。 (或)之前?
  • 在连接的 ON 子句中包含条件意味着将为 t2 中的每一行评估条件。对其进行评估以确定是否应连接 t2 行 - 因此在实际连接该行之前对其进行评估。希望这会有所帮助。
【解决方案3】:

您不应该在JOIN ON 条件中包含t.ID = '1',因为它不是连接表。 FROM 部分表上的条件应保留在 WHERE 子句中;而属于连接表的条件应该移动到join on子句中,以获得适当的外连接效果而不是内连接效果。

【讨论】:

  • 但是 Oracle 优化器没有检测到这一点吗?
  • @jarlh,应该是,但不确定优化器会选择执行什么。即使您尝试在 SQL Server 中执行相同的操作,也可能会看到相同的感觉。至少我见过......不确定优化器是否会中和它。
  • 很好的观察,但 ON 子句是 1) 执行 ID=1 和 2) 的所有其他 ID 的有效语法,并为 T2 保留填充为 NULL 的 ID。不使用它的真正原因是,结果性能比分别执行 1 和 2 的两个查询要差得多。
【解决方案4】:

不需要 OUTER JOIN。原因很简单,您在同一列上加入同一张表 - 不可能有不匹配!

因此要使用的查询是

 Select * 
 FROM T
 INNER  JOIN T t2    
 ON T.MasterID = t2.MasterID 
 Where t.ID = 1 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 1970-01-01
    • 2010-10-22
    • 2015-09-14
    • 1970-01-01
    • 2020-06-05
    • 2018-01-04
    相关资源
    最近更新 更多