Mysql中in和exists的区别 & not in、not exists、left join的相互转换问题

 更新时间:2023年09月16日 15:40:08   作者:心流时间  
这篇文章主要介绍了Mysql中in和exists的区别 & not in、not exists、left join的相互转换,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

数据准备

-- 建表
CREATE TABLE `xin_stu_t_bak` (
  `id` bigint NOT NULL COMMENT '主键',
  `relation_id` bigint DEFAULT NULL COMMENT '外键, 记录教师id',
  `student_name` varchar(30) DEFAULT NULL COMMENT '姓名',
  `student_age` bigint DEFAULT NULL COMMENT '年龄',
  `school` varchar(300) DEFAULT NULL COMMENT '学校',
  KEY `relationid` (`relation_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xin_teach_t_bak` (
  `id` bigint NOT NULL COMMENT '主键',
  `teacher_name` varchar(30) DEFAULT NULL COMMENT '教师姓名',
  `teacher_age` bigint DEFAULT NULL COMMENT '教师年龄',
  `school` varchar(300) DEFAULT NULL COMMENT '学校',
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 加索引
create index id on xin_stu_t_bak(relation_id);
create index id on xin_teach_t_bak(id);
-- 添数据
INSERT INTO lelele.xin_stu_t_bak (id,relation_id,student_name,student_age,school) VALUES
	 (1,NULL,'尤仁义1',11,'徐州中学'),
	 (2,1,'尤仁义2',12,'徐州中学'),
	 (3,NULL,'朱有理1',11,'徐州中学'),
	 (4,2,'朱有理2',12,'徐州中学'),
	 (5,2,'朱有理3',13,'徐州中学'),
	 (6,3,'宋昆明1',11,'徐州中学'),
	 (7,3,'宋昆明2',12,'徐州中学'),
	 (8,14,'宋昆明3',13,'徐州中学');
INSERT INTO lelele.xin_teach_t_bak (id,teacher_name,teacher_age,school) VALUES
	 (1,'王翠花1',31,'徐州中学'),
	 (2,'王翠花2',31,'徐州中学'),
	 (3,'王翠花3',33,'徐州中学'),
	 (4,'王翠花4',34,'徐州中学'),
	 (5,'王翠花5',35,'徐州中学'),
	 (1,'王翠花1',31,'徐州中学'),
	 (1,'王翠花1',31,'徐州中学'),
	 (2,'王翠花2',31,'徐州中学'),
	 (6,'王翠花6',31,'徐州中学'),
	 (7,'王翠花7',31,'徐州中学');
INSERT INTO lelele.xin_teach_t_bak (id,teacher_name,teacher_age,school) VALUES
	 (8,'王翠花8',33,'徐州中学'),
	 (9,'王翠花9',34,'徐州中学'),
	 (10,'王翠花10',35,'徐州中学'),
	 (11,'王翠花11',31,'徐州中学'),
	 (12,'王翠花12',31,'徐州中学'),
	 (13,'王翠花13',31,'徐州中学');

1. in 介绍

1.1 in中数据量的限制

在oracle中,int中数据集的大小超过1000会报错;
在mysql中,超过1000不会报错,但也是有数据量限制的,应该是4mb,但不建议数据集超过1000,
因为in是可以走索引的,但in中数据量过大索引就会失效

1.2 null值不参与in或not in,也就是说in and not in 并不是全量值,排除了null值

select * from xin_stu_t_bak a where a.relation_id in ( select id from xin_teach_t_bak b)

在这里插入图片描述

select * from xin_stu_t_bak a where a.relation_id not in ( select id from xin_teach_t_bak b)

在这里插入图片描述

select * from xin_stu_t_bak a

在这里插入图片描述

从此处可以看出,in和not in 加在一起并不是全量的值,排除了null值

1.3 in的执行逻辑

  • 当前的in子查询是B表驱动A表
  • mysql先将B表的数据一把查出来至于内存中
  • 遍历B表的数据,再去查A表(每次遍历都是一次连接交互,这里会耗资源)
  • 假设B有100000条记录,A有10条记录,会交互100000次数据库;再假设B有10条记录,A有100000记录,只会发生10次交互。

结论: in是先进行子查询,再与外面的数据进行循环遍历,属于子查询的结果集驱动外面的结果集,
当in子查询的结果集较小时,就形成了小表驱动大表,而两张表的驱动就是一张表的行数据去循环关联另一张表,
关联次数越少越好,所以小表去查询大表,次数更少,性能更高
in()适合B表比A表数据小的情况

2. exists介绍

2.1 exists + not exists 是全量数据

select * from xin_stu_t_bak a where exists ( select 1 from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

select * from xin_stu_t_bak a where not exists ( select 1 from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

exist + not exists 是全量数据,这点与in不同

2.2 exists的执行逻辑

  • 当前exists查询是A表驱动B表
  • 与in不同,exists将A的纪录数查询到内存,因此A表的记录数决定了数据库的交互次数
  • 假设A有10000条记录,B有10条记录,数据库交互次数为10000;假设A有10条,B有10000条,数据库交互次数为10。

结论:exists理论上就是boolean值,关联后查询到有值则是true数据留下,关联后查询没有值则是false数据舍弃;exists适合B表数据量大,A表数据量小的情况,与in相反

3. 小表驱动大表的好处

我们来看下面两个循环:

for (int i = 0; i<10000; i++){ 
	for(int j = 0; j<10; j++){
	}
}
for (int i = 0; i<10; i++){ 
	for(int j = 0; j<10000; j++){
	}
}

在java中,我们都知道上述的两个循环的时间复杂度都是一样的;
但在数据库中则是有区别的,
首先第一层循环,数据库只做一次交互一把将数据查出到缓存中,
而第二层循环的数据库交互次数决定于第一层循环数据量的大小。
对于数据库而言,交互次数越多越耗费资源,一次交互涉及了“连接-查找-断开”这些操作,是相当耗费资源的。
使用in时,B表驱动A
使用exists时,A表驱动B
所以我们写sql时应当遵循“小表驱动大表“的原则

4. in、not in、exists、not exists是否可以走索引(都可以)

in可以走索引,但数据量过大时就不走索引了not in、exist、not exists也都可以走索引

in

select * from xin_stu_t_bak a where a.relation_id in ( select id from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

select * from xin_stu_t_bak a where a.relation_id in (‘1', ‘2')

在这里插入图片描述

not in

select * from xin_stu_t_bak a where a.relation_id not in (‘1', ‘2')

在这里插入图片描述

exists

select * from xin_stu_t_bak a where exists ( select 1 from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

not exists

select * from xin_stu_t_bak a where not exists ( select 1 from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

5. not in、 not exists、left join语句相互转换(必须在表关联时,否则并不等同)

5.1 not in

select * from xin_stu_t_bak a where a.relation_id not in ( select id from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

5.2 not exists

select * from xin_stu_t_bak a where not exists ( select 1 from xin_teach_t_bak b where a.relation_id = b.id)

在这里插入图片描述

5.3 left join + is null

select a.* from xin_stu_t_bak a left join xin_teach_t_bak b on a.relation_id = b.id where b.id is null;

在这里插入图片描述

到此这篇关于Mysql中in和exists的区别 & not in、not exists、left join的相互转换的文章就介绍到这了,更多相关Mysql中in和exists区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • log引起的mysql不能启动的解决方法

    log引起的mysql不能启动的解决方法

    今天服务器挂了原来服务器的硬盘进行了数据转移 弄到mysql的时候发现里面log日志文件高达900MB
    2008-07-07
  • MySQL配置主从服务器(一主多从)

    MySQL配置主从服务器(一主多从)

    本文主要介绍了MySQL配置主从服务器,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • MySQL中创建表的三种方法汇总

    MySQL中创建表的三种方法汇总

    这篇文章主要介绍了MySQL中创建表的三种方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • MySQL查询结果复制到新表的方法(更新、插入)

    MySQL查询结果复制到新表的方法(更新、插入)

    下面小编就为大家带来一篇MySQL查询结果复制到新表的方法(更新、插入)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • MYSQL如何自动为查询数据的结果编上序号详解

    MYSQL如何自动为查询数据的结果编上序号详解

    这篇文章主要给大家介绍了关于MYSQL如何自动为查询数据的结果编上序号的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用mysql具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧。
    2017-11-11
  • MySQL创建数据表时设定引擎MyISAM/InnoDB操作

    MySQL创建数据表时设定引擎MyISAM/InnoDB操作

    这篇文章主要介绍了MySQL创建数据表时设定引擎MyISAM/InnoDB操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • mysql中获取一天、一周、一月时间数据的各种sql语句写法

    mysql中获取一天、一周、一月时间数据的各种sql语句写法

    今天抽时间整理了一篇mysql中与天、周、月有关的时间数据的sql语句的各种写法,部分是收集资料,全部手工整理,自己学习的同时,分享给大家,并首先默认创建一个表、插入2条数据,便于部分数据的测试,其中部分名词或函数进行了解释说明。直入主题
    2014-05-05
  • mysql多表查询的几种分类详细

    mysql多表查询的几种分类详细

    本文主要介绍了mysql多表查询的几种分类详细,主要包括3大分类,等值连接 vs 非等值连接,自连接 vs 非自连接,内连接 vs 外连接,文章介绍的非常详细,感兴趣的可以了解一下
    2022-02-02
  • mysql数据库的内外连接

    mysql数据库的内外连接

    这篇文章主要介绍了mysql数据库的内外连接,内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询,需要的朋友可以参考下
    2023-07-07
  • MySQL一键安装Shell脚本的实现

    MySQL一键安装Shell脚本的实现

    本文主要介绍了MySQL一键安装Shell脚本,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01

最新评论