在 LEFT JOIN 中使用 "ON .. AND" 和 "WHERE" 的区别
Difference between using "ON .. AND" and "WHERE" in LEFT JOIN
这两个查询在执行方面实际上是相同的还是有任何区别?如果它们相同,这两者之间会有任何性能差异吗?
1.
SELECT *
FROM TABLE_A tbl_a
LEFT JOIN TABLE_B tbl_b ON (tbl_a.srno_a = tbl_b.srno_b)
AND tbl_a.srno_a = 1997
和
2.
SELECT *
FROM TABLE_A tbl_a
LEFT JOIN TABLE_B tbl_b ON (tbl_a.srno_a = tbl_b.srno_b)
WHERE tbl_a.srno_a = 1997
在这里你可以看到不同之处:
如果你使用 WHERE 结果会更小。看样本。
样本
我的表
MariaDB [yourSchema]> select * from table1;
+--------+------------+
| id | val |
+--------+------------+
| 000001 | tabe 1 --1 |
| 000002 | tabe 1 --2 |
| 000003 | tabe 1 --3 |
| 000004 | tabe 1 --4 |
| 000005 | tabe 1 --5 |
| 000006 | tabe 1 --6 |
+--------+------------+
6 rows in set (0.00 sec)
MariaDB [yourSchema]> select * from table2;
+--------+------------+
| id | val |
+--------+------------+
| 000001 | tabe 2 --1 |
| 000002 | tabe 2 --2 |
| 000004 | tabe 2 --4 |
| 000005 | tabe 2 --5 |
| 000006 | tabe 2 --6 |
+--------+------------+
5 rows in set (0.00 sec)
MariaDB [yourSchema]>
加入 AND
MariaDB [yourSchema]> SELECT *
-> FROM table1 t1
-> LEFT JOIN table2 t2 ON t1.id = t2. id AND t2.val ='tabe 2 --4';
+--------+------------+--------+------------+
| id | val | id | val |
+--------+------------+--------+------------+
| 000004 | tabe 1 --4 | 000004 | tabe 2 --4 |
| 000001 | tabe 1 --1 | NULL | NULL |
| 000002 | tabe 1 --2 | NULL | NULL |
| 000003 | tabe 1 --3 | NULL | NULL |
| 000005 | tabe 1 --5 | NULL | NULL |
| 000006 | tabe 1 --6 | NULL | NULL |
+--------+------------+--------+------------+
6 rows in set (0.00 sec)
MariaDB [yourSchema]>
加入 WHERE
MariaDB [yourSchema]> SELECT *
-> FROM table1 t1
-> LEFT JOIN table2 t2 ON t1.id = t2. id
-> WHERE t2.val ='tabe 2 --4';
+--------+------------+--------+------------+
| id | val | id | val |
+--------+------------+--------+------------+
| 000004 | tabe 1 --4 | 000004 | tabe 2 --4 |
+--------+------------+--------+------------+
1 row in set (0.00 sec)
MariaDB [yourSchema]>
对于LEFT [OUTER] JOIN
,是基于多重性的根本区别。这是因为 LEFT/RIGHT/FULL 外连接 'preserve' 分别存在于 left/right 源集中的记录,即使它们不匹配:
即:左联接 不会 删除出现在左集中的任何行,无论联接条件如何。
-- the result of the LEFT join contains every LEFT row AT LEAST ONCE
-- then we throw away the post-join rows that we don't want
SELECT * FROM l
LEFT JOIN r ON r.id = l.id
WHERE l.x = q
-- the above is logically equivalent to the following
-- where the left set is restricted before the join
SELECT * FROM (SELECT * FROM l WHERE l.x = q) l2
LEFT JOIN r ON r.id = l2.id
-- however, it differs from just moving the condition as
-- the result of the LEFT join contains every LEFT row AT LEAST ONCE
-- (this includes the rows for which 'l.x = q' is NOT true!)
-- but we don't filter the post-join rows
SELECT * FROM l
LEFT JOIN r ON r.id = l.id
AND l.x = q
使用 OUTER JOIN
时,无法始终移动条件。对于 LEFT JOIN
,一个限制性连接条件 仅 依赖于左侧关系,它可能.. 错误。
如果它是 INNER JOIN
那么条件可以移动而不影响结果。这是因为 INNER JOIN 限制 两个连接集,因此没有 'AT LEAST ONCE' 子句。
只有 有效 查询才能对性能进行推理 - 查询执行计划将包含相关的执行信息。使用 'correct' 连接的行为会影响数据库执行查询的方式。
这两个查询在执行方面实际上是相同的还是有任何区别?如果它们相同,这两者之间会有任何性能差异吗?
1.
SELECT *
FROM TABLE_A tbl_a
LEFT JOIN TABLE_B tbl_b ON (tbl_a.srno_a = tbl_b.srno_b)
AND tbl_a.srno_a = 1997
和
2.
SELECT *
FROM TABLE_A tbl_a
LEFT JOIN TABLE_B tbl_b ON (tbl_a.srno_a = tbl_b.srno_b)
WHERE tbl_a.srno_a = 1997
在这里你可以看到不同之处:
如果你使用 WHERE 结果会更小。看样本。
样本
我的表
MariaDB [yourSchema]> select * from table1;
+--------+------------+
| id | val |
+--------+------------+
| 000001 | tabe 1 --1 |
| 000002 | tabe 1 --2 |
| 000003 | tabe 1 --3 |
| 000004 | tabe 1 --4 |
| 000005 | tabe 1 --5 |
| 000006 | tabe 1 --6 |
+--------+------------+
6 rows in set (0.00 sec)
MariaDB [yourSchema]> select * from table2;
+--------+------------+
| id | val |
+--------+------------+
| 000001 | tabe 2 --1 |
| 000002 | tabe 2 --2 |
| 000004 | tabe 2 --4 |
| 000005 | tabe 2 --5 |
| 000006 | tabe 2 --6 |
+--------+------------+
5 rows in set (0.00 sec)
MariaDB [yourSchema]>
加入 AND
MariaDB [yourSchema]> SELECT *
-> FROM table1 t1
-> LEFT JOIN table2 t2 ON t1.id = t2. id AND t2.val ='tabe 2 --4';
+--------+------------+--------+------------+
| id | val | id | val |
+--------+------------+--------+------------+
| 000004 | tabe 1 --4 | 000004 | tabe 2 --4 |
| 000001 | tabe 1 --1 | NULL | NULL |
| 000002 | tabe 1 --2 | NULL | NULL |
| 000003 | tabe 1 --3 | NULL | NULL |
| 000005 | tabe 1 --5 | NULL | NULL |
| 000006 | tabe 1 --6 | NULL | NULL |
+--------+------------+--------+------------+
6 rows in set (0.00 sec)
MariaDB [yourSchema]>
加入 WHERE
MariaDB [yourSchema]> SELECT *
-> FROM table1 t1
-> LEFT JOIN table2 t2 ON t1.id = t2. id
-> WHERE t2.val ='tabe 2 --4';
+--------+------------+--------+------------+
| id | val | id | val |
+--------+------------+--------+------------+
| 000004 | tabe 1 --4 | 000004 | tabe 2 --4 |
+--------+------------+--------+------------+
1 row in set (0.00 sec)
MariaDB [yourSchema]>
对于LEFT [OUTER] JOIN
,是基于多重性的根本区别。这是因为 LEFT/RIGHT/FULL 外连接 'preserve' 分别存在于 left/right 源集中的记录,即使它们不匹配:
即:左联接 不会 删除出现在左集中的任何行,无论联接条件如何。
-- the result of the LEFT join contains every LEFT row AT LEAST ONCE
-- then we throw away the post-join rows that we don't want
SELECT * FROM l
LEFT JOIN r ON r.id = l.id
WHERE l.x = q
-- the above is logically equivalent to the following
-- where the left set is restricted before the join
SELECT * FROM (SELECT * FROM l WHERE l.x = q) l2
LEFT JOIN r ON r.id = l2.id
-- however, it differs from just moving the condition as
-- the result of the LEFT join contains every LEFT row AT LEAST ONCE
-- (this includes the rows for which 'l.x = q' is NOT true!)
-- but we don't filter the post-join rows
SELECT * FROM l
LEFT JOIN r ON r.id = l.id
AND l.x = q
使用 OUTER JOIN
时,无法始终移动条件。对于 LEFT JOIN
,一个限制性连接条件 仅 依赖于左侧关系,它可能.. 错误。
如果它是 INNER JOIN
那么条件可以移动而不影响结果。这是因为 INNER JOIN 限制 两个连接集,因此没有 'AT LEAST ONCE' 子句。
只有 有效 查询才能对性能进行推理 - 查询执行计划将包含相关的执行信息。使用 'correct' 连接的行为会影响数据库执行查询的方式。