我有多个连接,包括mysql中的左连接。有两种方法可以做到这一点。
我可以把" ON"每次加入后的条件:
select * from A join B ON(A.bid = B.ID)join C ON(B.cid = C.ID)join D ON(c.did = D.ID)
我可以将它们全部放在一起" ON"子句:
select * from A join B join C join D ON(A.bid = B.ID AND B.cid = C.ID AND c.did = D.ID)
哪种方式更好?
如果我的查询中需要左连接或右连接,会有所不同吗?
答案 0 :(得分:5)
对于简单的用途,MySQL几乎不可避免地以相同的方式执行它们,因此它是一种偏好和可读性(这是一个很好的辩论主题)。
然而,对于更复杂的查询,特别是具有OUTER JOIN
的可能成为磁盘和io绑定的聚合查询 - 在不使用带有OUTER JOIN查询的WHERE子句时可能会有性能和看不见的含义。
运行8分钟或.8秒的查询之间的差异可能最终取决于WHERE
子句,特别是因为它与索引(How MySQL uses Indexes)相关:WHERE
子句是向查询优化器提供执行工作所需信息的核心部分,并告诉引擎如何以最有效的方式执行查询。
来自How MySQL Optimizes Queries using WHERE:
“本节讨论可以进行处理的优化 WHERE子句...加入表的最佳连接组合是 通过尝试所有可能性找到。如果ORDER BY和中的所有列 GROUP BY子句来自同一个表,该表是首选 首先加入。“
对于连接中的每个表,构造一个更简单的WHERE来获得快速 WHERE评估表,并尽快跳过行 可能
一些例子:
全表扫描(类型=全部),EXTRA中没有Using where
[SQL] SELECT cr.id,cr2.role FROM CReportsAL cr
LEFT JOIN CReportsCA cr2
ON cr.id = cr2.id AND cr.role = cr2.role AND cr.util = 1000
[Err] Out of memory
使用where
优化结果,使用索引(Using where
,Using index
):
[SQL] SELECT cr.id,cr2.role FROM CReportsAL cr
LEFT JOIN CReportsCA cr2
ON cr.id = cr2.id
WHERE cr.role = cr2.role
AND cr.util = 1000
515661 rows in set (0.124s)
**** ON / WHERE的组合 - 相同的结果 - EXPLAIN
*******
[SQL] SELECT cr.id,cr2.role FROM CReportsAL cr
LEFT JOIN CReportsCA cr2
ON cr.id = cr2.id
AND cr.role = cr2.role
WHERE cr.util = 1000
515661 rows in set (0.121s)
MySQL通常足够聪明,能够找出如上所述的简单查询,并且会以相似的方式执行它们,但在某些情况下它不会执行它们。
外部加入查询效果
由于LEFT JOIN和RIGHT JOIN都是OUTER JOINS(Great in depth review here)出现了笛卡尔积的问题,因此必须避免使用表扫描,以便消除查询不需要的尽可能多的行尽可能快。
WHERE
,索引和查询优化器一起使用可能完全消除了笛卡儿产品在仔细使用AVERAGE
,GROUP BY
等聚合函数时所带来的问题,SUM
,DISTINCT
等等。通过用户的正确索引和WHERE子句的使用,可以实现运行时间减少的数量级。
<强>最后强>
同样,对于大多数查询,查询优化器将以相同的方式执行这些 - 使其成为一种偏好方式,但当查询优化变得重要时,WHERE
是一个非常重要的工具。通过将索引col指定为附加的ON..AND ON子句,我已经看到INNER JOIN
在某些情况下性能有所提高,但我无法告诉您原因。
答案 1 :(得分:3)
将ON子句与它适用的JOIN放在一起。
原因是: