MySQL的not exists和not in比较和优化

1.背景

没什么背景,就是想记录下。

2.本文使用的表结构以及数据

本文使用的数据库为MySQL 5.7,下面是使用到的数据,数据量不多,但是能测出一点区别。

--- 学生表
create table student (
    sno varchar(20) comment '学号',
    sname varchar(20) comment '姓名',
    sd varchar(10) comment '系',
    sgae int comment '年龄',
    sex int comment '性别',
    addr varchar(50) comment '家庭住址',
    primary key(sno) 
);

--- 课程表
create table course (
    cno varchar(20) comment '课程号',
    cname varchar(20) comment '课程名',
    pcno varchar(50) comment '先修课程号',
    primary key(cno)
);
    
--- 学生选课
create table sc(
    sno varchar(20) comment '学号',
    cno varchar(20) comment '课程号',
    grade decimal(4,2) comment '成绩',
    primary key(sno,cno),
    foreign key(sno) references student(sno),
    foreign key(cno) references course(cno)
);
    

--- 插入数据
insert into student values('s1000001','张三','工学部',18,1,'北京'),('s1000002','张四','工学部',18,1,'上海'),('s1000003','张五','工学部',19,1,'广州'),('s1000004','张六','工学部',17,1,'深圳'),('s1000005','张七','工学部',18,1,'北京'),('s1000006','张八','工学部',19,1,'上海'),('s1000007','张九','工学部',20,1,'广州'),('s1000008','张十','工学部',18,1,'深圳'),('s1000009','李三','工学部',17,1,'北京'),('s1000010','李四','工学部',16,1,'上海'),('s1000011','李五','工学部',19,1,'广州');

insert into course values('c1001','操作系统',null),('c1002','计算机组成原理',null),('c1003','数据结构',null),('c1004','计算机网络',null),('c1005','算法',null),('c1006','软件工程概率',null),('c1007','离散数学','c1008'),('c1008','高等数学',null);


insert into sc values('s1000001','c1001',3.8),('s1000001','c1002',4.3),('s1000001','c1003',4.6),('s1000001','c1004',4.0),('s1000001','c1005',4.9),('s1000001','c1006',4.9),('s1000001','c1007',4.9),('s1000001','c1008',2.7),('s1000002','c1001',3.6),('s1000002','c1002',4.9),('s1000002','c1003',4.9),('s1000002','c1004',4.9),('s1000002','c1005',4.9),('s1000002','c1006',4.9),('s1000002','c1007',3.1),('s1000002','c1008',4.9),('s1000003','c1001',3.9),('s1000003','c1002',3.5),('s1000003','c1003',3.2),('s1000003','c1004',2.4),('s1000003','c1005',4.9),('s1000003','c1006',4.9),('s1000003','c1007',3.1),('s1000003','c1008',3.3),('s1000004','c1001',3.2),('s1000004','c1002',4.9),('s1000004','c1003',3.3),('s1000004','c1004',2.8),('s1000004','c1005',4.9),('s1000004','c1006',3.2),('s1000004','c1007',4.9),('s1000004','c1008',3.9),('s1000005','c1001',4.2),('s1000005','c1002',4.9),('s1000005','c1003',4.9),('s1000005','c1004',2.7),('s1000005','c1005',3.9),('s1000005','c1006',2.1),('s1000005','c1007',4.9),('s1000005','c1008',4.9),('s1000006','c1001',4.9),('s1000006','c1002',4.9),('s1000006','c1003',3.5),('s1000006','c1004',3.4),('s1000006','c1005',4.9),('s1000006','c1006',3.4),('s1000006','c1007',3.2),('s1000006','c1008',4.9),('s1000007','c1001',3.2),('s1000007','c1002',3.4),('s1000007','c1003',1.9),('s1000007','c1004',3.0),('s1000007','c1005',3.6),('s1000007','c1006',4.9),('s1000007','c1007',3.5),('s1000007','c1008',4.9),('s1000008','c1001',3.4),('s1000008','c1002',4.9),('s1000008','c1003',3.2),('s1000008','c1004',2.6),('s1000008','c1005',4.9),('s1000008','c1006',3.9),('s1000008','c1007',3.9),('s1000008','c1008',4.9),('s1000009','c1001',3.7),('s1000009','c1002',2.5),('s1000009','c1003',3.1),('s1000009','c1004',4.9),('s1000009','c1005',2.9),('s1000009','c1006',3.1),('s1000009','c1007',4.9),('s1000009','c1008',1.9),('s1000010','c1001',3.5),('s1000010','c1002',4.6),('s1000010','c1003',3.9),('s1000010','c1004',3.9),('s1000010','c1005',4.9),('s1000010','c1006',3.3),('s1000010','c1007',3.6),('s1000010','c1008',4.9)

3.not in执行效果

使用not in查看没有选修任何课程的学生,耗时0.01s:

select s.* from student s where s.sno not in (select a.sno from sc a);
+----------+--------+-----------+------+------+--------+
| sno      | sname  | sd        | sgae | sex  | addr   |
+----------+--------+-----------+------+------+--------+
| s1000011 | 李五   | 工学部    |   19 |    1 | 广州   |
+----------+--------+-----------+------+------+--------+
1 row in set (0.01 sec)

4.not exists执行效果

使用not exists查看没有选修任何课程的学生,耗时0.03s:

select s.* from student s where not exists (select 1 from sc a where a.sno=s.sno);
+----------+--------+-----------+------+------+--------+
| sno      | sname  | sd        | sgae | sex  | addr   |
+----------+--------+-----------+------+------+--------+
| s1000011 | 李五   | 工学部    |   19 |    1 | 广州   |
+----------+--------+-----------+------+------+--------+
1 row in set (0.03 sec)

5.优化

上面的not in和not exists是等价的,但是not exists明显比not in慢。在数据量很大的情况下,是不推荐使用这两个的,这种情况下,我们可以将sql改为left join的方式。

5.1.left join

left join顾名思义为左连接,语法为:

select a.* from a left join b on a.id = b.id [where ……]

left join语法中on和where的执行顺序为:先执行on生成临时表,再执行where对临时表做过滤。

​on 条件是在生成临时表时使用的条件,它不管 on 中的条件是否为真,都会返回左边表中的记录,以下面的两张表为例,用a表作为左表,b表作为右表,执行left join,返回4条记录(注意不是3条!)。

mysql> select * from tb1 a;
+------+
| id   |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

mysql> select * from tb2 b;
+------+
| id   |
+------+
|    1 |
|    2 |
|    4 |
|    2 |
+------+
4 rows in set (0.00 sec)

mysql> select a.* from tb1 a left join tb2 b on a.id=b.id;
+------+
| id   |
+------+
|    1 |
|    2 |
|    2 |
|    3 |
+------+
4 rows in set (0.00 sec)

NOTE:

对于left join,部分同学误解为返回的记录数一定是等于左表的记录数,其实不是的。

  • 在没有where的条件下,执行on时,以左表为基准,去右表匹配,如从a表拿id=1去b表匹配,b表有3条id=1的记录,此时就会返回3条记录。
  • 在有where的条件下,执行完on后得到的结果需要经过where条件去过滤。
    综上所述,left join的结果集不一定等于左表。

5.2.not in和not exists改造为left join

改为left join的语法为,耗时0.00s:

select s.* from student s  left join sc a on s.sno=a.sno where a.sno is null;
+----------+--------+-----------+------+------+--------+
| sno      | sname  | sd        | sgae | sex  | addr   |
+----------+--------+-----------+------+------+--------+
| s1000011 | 李五   | 工学部    |   19 |    1 | 广州   |
+----------+--------+-----------+------+------+--------+
1 row in set (0.00 sec)

前面提到,先执行on生成临时表,因为student是左表,所以执行on时,左表的11条记录中有10条记录每条能匹配到8条课程分数记录,而sno为s1000011的记录没有匹配到数据,所以右边补上NULL。总共得到的数据为81条:

mysql> select s.*,a.* from student s  left join sc a on s.sno=a.sno;
+----------+--------+-----------+------+------+--------+----------+-------+-------+
| sno      | sname  | sd        | sgae | sex  | addr   | sno      | cno   | grade |
+----------+--------+-----------+------+------+--------+----------+-------+-------+
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1001 |  3.80 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1002 |  4.30 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1003 |  4.60 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1004 |  4.00 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1005 |  4.90 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1006 |  4.90 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1007 |  4.90 |
| s1000001 | 张三   | 工学部    |   18 |    1 | 北京   | s1000001 | c1008 |  2.70 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1001 |  3.60 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1002 |  4.90 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1003 |  4.90 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1004 |  4.90 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1005 |  4.90 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1006 |  4.90 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1007 |  3.10 |
| s1000002 | 张四   | 工学部    |   18 |    1 | 上海   | s1000002 | c1008 |  4.90 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1001 |  3.90 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1002 |  3.50 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1003 |  3.20 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1004 |  2.40 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1005 |  4.90 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1006 |  4.90 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1007 |  3.10 |
| s1000003 | 张五   | 工学部    |   19 |    1 | 广州   | s1000003 | c1008 |  3.30 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1001 |  3.20 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1002 |  4.90 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1003 |  3.30 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1004 |  2.80 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1005 |  4.90 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1006 |  3.20 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1007 |  4.90 |
| s1000004 | 张六   | 工学部    |   17 |    1 | 深圳   | s1000004 | c1008 |  3.90 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1001 |  4.20 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1002 |  4.90 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1003 |  4.90 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1004 |  2.70 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1005 |  3.90 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1006 |  2.10 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1007 |  4.90 |
| s1000005 | 张七   | 工学部    |   18 |    1 | 北京   | s1000005 | c1008 |  4.90 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1001 |  4.90 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1002 |  4.90 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1003 |  3.50 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1004 |  3.40 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1005 |  4.90 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1006 |  3.40 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1007 |  3.20 |
| s1000006 | 张八   | 工学部    |   19 |    1 | 上海   | s1000006 | c1008 |  4.90 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1001 |  3.20 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1002 |  3.40 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1003 |  1.90 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1004 |  3.00 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1005 |  3.60 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1006 |  4.90 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1007 |  3.50 |
| s1000007 | 张九   | 工学部    |   20 |    1 | 广州   | s1000007 | c1008 |  4.90 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1001 |  3.40 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1002 |  4.90 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1003 |  3.20 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1004 |  2.60 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1005 |  4.90 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1006 |  3.90 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1007 |  3.90 |
| s1000008 | 张十   | 工学部    |   18 |    1 | 深圳   | s1000008 | c1008 |  4.90 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1001 |  3.70 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1002 |  2.50 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1003 |  3.10 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1004 |  4.90 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1005 |  2.90 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1006 |  3.10 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1007 |  4.90 |
| s1000009 | 李三   | 工学部    |   17 |    1 | 北京   | s1000009 | c1008 |  1.90 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1001 |  3.50 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1002 |  4.60 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1003 |  3.90 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1004 |  3.90 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1005 |  4.90 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1006 |  3.30 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1007 |  3.60 |
| s1000010 | 李四   | 工学部    |   16 |    1 | 上海   | s1000010 | c1008 |  4.90 |
| s1000011 | 李五   | 工学部    |   19 |    1 | 广州   | NULL     | NULL  |  NULL |
+----------+--------+-----------+------+------+--------+----------+-------+-------+

执行where后的条件: a.sno is null 后返回的记录即为所需要的记录。

6.总结

虽然本次的测试的记录数量并不多,但是可以看出来not in是比not exists慢的,而无论是两者中的哪一个都没有left join快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值