mysqlsqlleftrightinnerjoin区别及效率⽐较⼀.Join语法概述
join ⽤于多表中字段之间的联系,语法如下:
... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona
table1:左表;table2:右表。
JOIN 按照功能⼤致分为如下三类:
INNER JOIN(内连接,或等值连接):取得两个表中存在连接匹配关系的记录。
LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并⽆对应匹配记录。
RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并⽆匹配对应记录。注意:mysql不⽀持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join.
接下来给出⼀个列⼦⽤于解释下⾯⼏种分类。如下两个表(A,B)
mysql> select A.id,A.name,B.name from A,B where A.id=B.id;
+----+-----------+-------------+
| id | name      | name            |
+----+-----------+-------------+
|  1 | Pirate      | Rutabaga      |
|  2 | Monkey    | Pirate            |
|  3 | Ninja        | Darth Vader |
|  4 | Spaghetti  | Ninja            |
+----+-----------+-------------+
4 rows in set (0.00 sec)
⼆.Inner join
内连接,也叫等值连接,inner join产⽣同时符合A和B的⼀组数据。
mysql> select * from A inner join B on A.name = B.name;
+----+--------+----+--------+
| id | name  | id | name  |
+----+--------+----+--------+
sql left join 多表连接
|  1 | Pirate |  2 | Pirate |
|  3 | Ninja  |  4 | Ninja  |
+----+--------+----+--------+
三.Left join
mysql> select * from A left join B on A.name = B.name;
#或者:select * from A left outer join B on A.name = B.name;
+----+-----------+------+--------+
| id | name      | id  | name  |
+----+-----------+------+--------+
|  1 | Pirate    |    2 | Pirate |
|  2 | Monkey    | NULL | NULL  |
|  3 | Ninja    |    4 | Ninja  |
|  4 | Spaghetti | NULL | NULL  |
+----+-----------+------+--------+
4 rows in set (0.00 sec)
left join,(或left outer join:在Mysql中两者等价,推荐使⽤left join.)左连接从左表(A)产⽣⼀套完整的记录,与匹配的记录(右表(B)) .如果没有匹配,右侧将包含null。
如果想只从左表(A)中产⽣⼀套记录,但不包含右表(B)的记录,可以通过设置where语句来执⾏,如下:
mysql> select * from A left join B on A.name=B.name where A.id is null or B.id is null;
+----+-----------+------+------+
| id | name      | id  | name |
+----+-----------+------+------+
|  2 | Monkey    | NULL | NULL |
|  4 | Spaghetti | NULL | NULL |
+----+-----------+------+------+
2 rows in set (0.00 sec)
同理,还可以模拟inner join. 如下:
mysql> select * from A left join B on A.name=B.name where A.id is not null and B.id is not null;
+----+--------+------+--------+
| id | name  | id  | name  |
+----+--------+------+--------+
|  1 | Pirate |    2 | Pirate |
|  3 | Ninja  |    4 | Ninja  |
+----+--------+------+--------+
2 rows in set (0.00 sec)
求差集:
根据上⾯的例⼦可以求差集,如下:
SELECT * FROM A LEFT JOIN B ON A.name = B.name
WHERE B.id IS NULL
union
SELECT * FROM A right JOIN B ON A.name = B.name
WHERE A.id IS NULL;
# 结果
+------+-----------+------+-------------+
| id  | name      | id  | name        |
+------+-----------+------+-------------+
|    2 | Monkey    | NULL | NULL        |
|    4 | Spaghetti | NULL | NULL        |
| NULL | NULL      |    1 | Rutabaga    |
| NULL | NULL      |    3 | Darth Vader |
+------+-----------+------+-------------+
四.Right join
mysql> select * from A right join B on A.name = B.name;
+------+--------+----+-------------+
| id  | name  | id | name        |
+------+--------+----+-------------+
| NULL | NULL  |  1 | Rutabaga    |
|    1 | Pirate |  2 | Pirate      |
| NULL | NULL  |  3 | Darth Vader |
|    3 | Ninja  |  4 | Ninja      |
+------+--------+----+-------------+
4 rows in set (0.00 sec)
同left join。
五.Cross join
cross join:交叉连接,得到的结果是两个表的乘积,即
笛卡尔(Descartes)乘积⼜叫直积。假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。可以扩展到多个集合的情况。类似的例⼦有,如果A表⽰某学校学⽣的集合,B表⽰该学校所有课程的集合,则A与B的笛卡尔积表⽰所有可能的选课情况。
mysql> select * from A cross join B;
+----+-----------+----+-------------+
| id | name      | id | name        |
+----+-----------+----+-------------+
|  1 | Pirate    |  1 | Rutabaga    |
|  2 | Monkey    |  1 | Rutabaga    |
|  3 | Ninja    |  1 | Rutabaga    |
|  4 | Spaghetti |  1 | Rutabaga    |
|  1 | Pirate    |  2 | Pirate      |
|  2 | Monkey    |  2 | Pirate      |
|  3 | Ninja    |  2 | Pirate      |
|  4 | Spaghetti |  2 | Pirate      |
|  1 | Pirate    |  3 | Darth Vader |
|  2 | Monkey    |  3 | Darth Vader |
|  3 | Ninja    |  3 | Darth Vader |
|  4 | Spaghetti |  3 | Darth Vader |
|  1 | Pirate    |  4 | Ninja      |
|  2 | Monkey    |  4 | Ninja      |
|  3 | Ninja    |  4 | Ninja      |
|  4 | Spaghetti |  4 | Ninja      |
+----+-----------+----+-------------+
16rows in set (0.00 sec)
#再执⾏:mysql> select * from A inner join B; 试⼀试
#在执⾏mysql> select * from A cross join B on A.name = B.name; 试⼀试
实际上,在 MySQL 中(仅限于 MySQL) CROSS JOIN 与 INNER JOIN 的表现是⼀样的,在不指定 ON 条件得到的结果都是笛卡尔积,反之取得两个表完全匹配的结果。
INNER JOIN 与 CROSS JOIN 可以省略 INNER 或 CROSS 关键字,因此下⾯的 SQL 效果是⼀样的:
... FROM table1 INNER JOIN table2
... FROM table1 CROSS JOIN table2
... FROM table1 JOIN table2
六.Full join
mysql> select * from A left join B on B.name = A.name
-> union
-> select * from A right join B on B.name = A.name;
+------+-----------+------+-------------+
| id  | name      | id  | name        |
+------+-----------+------+-------------+
|    1 | Pirate    |    2 | Pirate      |
|    2 | Monkey    | NULL | NULL        |
|    3 | Ninja    |    4 | Ninja      |
|    4 | Spaghetti | NULL | NULL        |
| NULL | NULL      |    1 | Rutabaga    |
| NULL | NULL      |    3 | Darth Vader |
+------+-----------+------+-------------+
6 rows in set (0.00 sec)
全连接产⽣的所有记录(双⽅匹配记录)在表A和表B。如果没有匹配,则对⾯将包含null。
七.性能优化
1.显⽰(explicit) inner join VS 隐式(implicit) inner join
如:
select * from
table a inner join table b
on a.id = b.id;
VS
select a.*, b.*
from table a, table b
where a.id = b.id;
我在数据库中⽐较(10w数据)得之,它们⽤时⼏乎相同,第⼀个是显⽰的inner join,后⼀个是隐式的inner join。
2.left join/right join VS inner join
尽量⽤inner join.避免 LEFT JOIN 和 NULL.
在使⽤left join(或right join)时,应该清楚的知道以下⼏点:
(1). on与 where的执⾏顺序
ON 条件(“A LEFT JOIN B ON 条件表达式”中的ON)⽤来决定如何从 B 表中检索数据⾏。如果 B 表中没有任何⼀⾏数据匹配 ON 的条件,将会额外⽣成⼀⾏所有列为 NULL 的数据,在匹配阶段 WHER
E ⼦句的条件都不会被使⽤。仅在匹配阶段完成以后,WHERE ⼦句条件才会被使⽤。它将从匹配阶段产⽣的数据中检索过滤。
所以我们要注意:在使⽤Left (right) join的时候,⼀定要在先给出尽可能多的匹配满⾜条件,减少Where的执⾏。如:
PS, 这部分有些不妥,感谢 wxweven 指正:
这部分的内容,博主写的有些⽋妥当,不知道博主有没有实际运⾏测试过,下⾯说说我的看法:
(1)⾸先关于on和where的⽤法,如果直接把where⾥⾯的条件拿到on⾥⾯去,结果是跟原来的不⼀致的,所以博主说的“在使⽤Left (right) join的时候,⼀定要在先给出尽可能多的匹配满⾜条件,减少Where的执⾏”是不成⽴的,因为筛选条件放在on或者where,产⽣的是不同的结果,不能说为了性能就把where中的条件放到on中。
可参考
PASS
select * from A
inner join B on B.name = A.name
left join C on C.name = B.name
left join D on D.id = C.id
where C.status>1and D.status=1;
Great

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。