3

我想知道为什么这个查询仍然可以完美运行。我认为 WHERE 子句总是必须以WHERE?

    SELECT `persons`.*
    FROM `persons`
    LEFT JOIN `team_memberships`
    ON (`team_memberships`.`participant` = `persons`.`id`)
    JOIN `teams`
    ON (`teams`.`id` = `team_memberships`.`team`)
    JOIN `departments`
    ON (`departments`.`id` = `teams`.`department`)
    JOIN `areas`
    ON (`areas`.`id` = `departments`.`area`)
    JOIN `companies`
    ON (`companies`.`id` = `areas`.`company`)

    [NO WHERE HERE]

    AND `persons`.`id` = ?
4

6 回答 6

6

您刚刚在子句中添加了AND一个ON。该ON子句仅计算布尔值真或假,因此允许使用AND布尔OR运算符,并且所有关于括号等的常用规则也适用。

将特定于特定连接表的条件从您的WHERE子句移动到适当的ON子句中通常是有利的 - 如果没有其他原因,只是为了提高可读性。

在继续连接其他表之前限制连接的结果是合乎逻辑的* ,而不是返回一个大的结果集,然后在最后用一个WHERE子句过滤它。我说*逻辑是因为 DBMS 通常会优化您的查询,因此无论如何都会发生这种情况……但并非总是如此……有时可以通过在连接处进行过滤来改善性能不佳的查询(有时反之亦然)。

例如,如果您知道您只对 25 岁以上的人感兴趣,则有意义的是JOIN persons ON persons.id = team_memberships.participant AND persons.age > 25,而不是包含仅与年轻朋克有关的后续表格的所有结果,以便在最后再次过滤这些结果用你的WHERE persons.age > 25条款。

我的理解是,在附加表达式的情况下,连接性能可能会因子ON句中的附加表达式而降低:

  • 导致对联接中的每一行进行评估(因此我age > 25上面的示例可能属于此类别),或者

  • 依赖于一个/两个连接表中的非索引列,否则连接将仅依赖于索引列。

因此,即使它使特定的连接变慢,它仍然可能证明值得在连接时从结果集中剥离年轻的朋克,因为此时较小的结果集可能会为后续连接带来很大的性能提升。但是,如果将它们包含在连接中只会导致记录数量略有增加,那么实际上将它们包含在连接中然后在WHERE子句中将它们过滤掉可能会更快。

但我欢迎评论澄清/纠正我的理解。


编辑:根据下面的@ITroubs 评论,我真的应该澄清一下,如果连接是一个,INNER JOIN那么无论附加过滤条件是否在ONorWHERE子句中,最终结果集都将是相同的,但是例如在 OP 的原始示例LEFT JOIN ON team_memberships中如果过滤条件从 移动到 ,则产生完全不同的结果WHERELEFT JOIN ... ON ...

于 2013-03-20T14:54:27.720 回答
2

如果我没记错的话,mysql 会按如下方式执行您的查询:

SELECT `persons`.*
FROM `persons`
LEFT JOIN `team_memberships`
ON (`team_memberships`.`participant` = `persons`.`id`)
JOIN `teams`
ON (`teams`.`id` = `team_memberships`.`team`)
JOIN `departments`
ON (`departments`.`id` = `teams`.`department`)
JOIN `areas`
ON (`areas`.`id` = `departments`.`area`)
JOIN `companies`
ON ((`companies`.`id` = `areas`.`company`) AND `persons`.`id` = ?')
于 2013-03-20T14:54:15.290 回答
0

最后一个 AND 不是 WHERE 子句的一部分,它是 JOIN 子句的一部分

于 2013-03-20T14:54:43.550 回答
0

它之所以有效,是因为您实际上没有WHERE子句,您的条件AND persons.id = ?是最后一个子句的一部分JOIN

于 2013-03-20T14:54:47.367 回答
0

它实际上意味着

join  `companies` on ON (`companies`.`id` = `areas`.`company`) AND persons.id = ?

因此,由于您正在执行内部连接 ​​- 它*几乎*等效。一旦你切换到 puter join 或复杂查询 - 有些东西会中断。

于 2013-03-20T14:55:28.523 回答
-1

这是有效的,请参阅http://dev.mysql.com/doc/refman/5.0/en/join.html,但请注意它们如何使用括号。

于 2013-03-20T14:55:49.273 回答