我想知道为什么这个查询仍然可以完美运行。我认为 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` = ?

最佳答案

您刚刚在 AND 子句中添加了 ONON 子句只是计算一个 bool 值真或假,所以 AND 和例如 OR bool 运算符是允许的,所有关于括号等的常用规则也适用。

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

在继续连接其他表之前限制连接的结果是合乎逻辑的*,而不是返回一个大的结果集,然后在最后用 WHERE 子句过滤它。我说 *logical 是因为 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,那么无论附加过滤条件是否在 ONWHERE 子句中,最终结果集都将相同,但例如在 OP 的原始语句中例如,如果过滤条件从 LEFT JOIN ON team_memberships 移动到 WHERELEFT JOIN ... ON ... 将产生完全不同的结果集。

    关于php - 特殊行为 : AND without WHERE still works,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15526985/

    10-16 08:26