MySQL-外连接
左右连接并不区分大小表,left join会先整表扫描左边的表,再扫描右边的表;同理right join会先扫描右边的表,再扫描左边的表;内连接的话是不确定的,会根据数据量,先扫描整表扫描小表,在扫描右表。
外连接的过滤条件放在where和on后边是不同的,中间的过滤条件应该放在on连接,确保使用的是外连接,最后的过滤应该放在where后边,对结果集进行的进一步筛选。像搜索不存在,带有一定限制条件的场景,限制条件一般加到on后边,where一般判断null即可。这个过滤条件的位置一定要注意
1 | mysql> select * from student; |
一、left join
1 | select a.*,b.* from student a left join exams b on a.uid = b.uid |
1 | mysql> select a.*,b.* from student a left join exams b on a.uid = b.uid; |
二、right join
1 | mysql> select a.*,b.* from student a right join exams b on a.uid = b.uid; |
1 | mysql> select a.*,b.* from student a right join exams b on a.uid = b.uid; |
explain 分析:
1 | mysql> explain select a.*,b.* from student a right join exams b on a.uid = b.uid; |
现在有这么一个情景:我们要查询没有考过试的学生
我们可以使用子连接
1
select * from student where uid not in (select uid from exams);
1
2
3
4
5
6
7
8
9mysql> select * from student where uid not in (select uid from exams);
+-----+--------+-----+-----+
| uid | name | age | sex |
+-----+--------+-----+-----+
| 6 | weiwie | 20 | M |
+-----+--------+-----+-----+
1 row in set (0.00 sec)
mysql>但是子链接有个问题,我们使用
not in有时候是使用不到索引的,同时可能会产生中间表,这样效率并不高1
2
3
4
5
6
7
8
9
10
11
12mysql> explain select * from student where uid not in (select uid from exams);
+----+-------------+---------+------------+------+---------------+---------+---------+--------------------+------+----------+--------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra
|
+----+-------------+---------+------------+------+---------------+---------+---------+--------------------+------+----------+--------------------------------------+
| 1 | SIMPLE | student | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | NULL
|
| 1 | SIMPLE | exams | NULL | ref | PRIMARY | PRIMARY | 4 | school.student.uid | 2 | 100.00 | Using where; Not exists; Using index |
+----+-------------+---------+------------+------+---------------+---------+---------+--------------------+------+----------+--------------------------------------+
2 rows in set, 1 warning (0.00 sec)
mysql>使用左连接
1
select a.* from student a left join exams b on a.uid = b.uid where b.cid is null;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20mysql> select a.* from student a left join exams b on a.uid = b.uid where b.cid is null;
+-----+--------+-----+-----+
| uid | name | age | sex |
+-----+--------+-----+-----+
| 6 | weiwie | 20 | M |
+-----+--------+-----+-----+
1 row in set (0.01 sec)
mysql> explain select a.* from student a left join exams b on a.uid = b.uid where b.cid is null;
+----+-------------+-------+------------+------+---------------+---------+---------+--------------+------+----------+--------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra
|
+----+-------------+-------+------------+------+---------------+---------+---------+--------------+------+----------+--------------------------------------+
| 1 | SIMPLE | a | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | NULL
|
| 1 | SIMPLE | b | NULL | ref | PRIMARY | PRIMARY | 4 | school.a.uid | 2 | 10.00 | Using where; Not exists; Using index |
+----+-------------+-------+------------+------+---------------+---------+---------+--------------+------+----------+--------------------------------------+
2 rows in set, 1 warning (0.01 sec)
mysql>
查看没有参加课程号为3考试的学生
1 | select a.* from student a |
1 | mysql> select a.* from student a left join exams b on a.uid = b.uid and b.cid = 3 where b.cid is null; |
explain 查询
1 | mysql> explain select a.* from student a left join exams b on a.uid = b.uid and b.cid = 3 where b.cid is null; |