前面我们讲解了索引的存储结构,B+Tree的索引结构,以及索引最左侧匹配原则及讲解一下常用的SQL语句的优化建议,今天我们来详细讲解一下 我们经常使用的 join, exist, in三者的区别
新建表结构 user, user_info
#新建表结构 user
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`id_card` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '身份证ID',
`user_name` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名字',
`age` int NOT NULL COMMENT '年龄',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表'
#新建订单表 order_info
CREATE TABLE `order_info` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`order_id` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单ID',
`user_name` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名字',
`address` char(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='订单表'
先插入测试数据, 插入 5条user 测试数据 2条订单数据
INSERT INTO `test`.`user` (`id`, `id_card`, `user_name`, `age`) VALUES (1, '11', 'aa', 10);
INSERT INTO `test`.`user` (`id`, `id_card`, `user_name`, `age`) VALUES (2, '22', 'bb', 20);
INSERT INTO `test`.`user` (`id`, `id_card`, `user_name`, `age`) VALUES (3, '33', 'cc', 30);
INSERT INTO `test`.`user` (`id`, `id_card`, `user_name`, `age`) VALUES (4, '44', 'dd', 40);
INSERT INTO `test`.`user` (`id`, `id_card`, `user_name`, `age`) VALUES (5, '55', 'ee', 50);
#2条订单数据
INSERT INTO `test`.`order_info` (`id`, `order_id`, `user_name`, `address`) VALUES (1, '1', 'aa', '北京');
INSERT INTO `test`.`order_info` (`id`, `order_id`, `user_name`, `address`) VALUES (2, '2', 'bb', '上海');
我们查看下存在订单的用户有哪些?
select * from user where user_name in (select user_name from order_info );
explain select * from user where user_name in (select user_name from order_info )
我们看下Explain执行分析
前面我们使用了in来进行查询, 现在我们使用 exists来替换 in,实现查询效果
select * from user where exists (select user_name from order_info where user.user_name = order_info.user_name);
explain select * from user where exists (select user_name from order_info where user.user_name = order_info.user_name);
我们看下Explain执行分析
前面我们尝试用 in 和 exists 来对比
我们都知道 如果涉及子查询的时候,我们都是小表驱动大表,先查小表,然后查大表,这就导致了in和exists用法的区别
简单通俗来讲就是下面的案例
如果 order表有1w数据,user表有10条数据, order是大表, user是小表, 采用 in 内小外大的用法
如果 user表有1w数据, order表有10条数据,上面的明显是错误的用法,采用 exists的 外小内大的用法
前面我们尝试用 in 和 exists 来对比,加上索引后,对比下 二者的结果
二者全部都使用了索引
alter table user add index idx_name(user_name);
alter table order_info add index idx_name(user_name);
explain select * from user where user_name in (select user_name from order_info )
explain select * from user where exists (select user_name from order_info where user.user_name = order_info.user_name);
explain select * from user where user_name not in (select user_name from order_info )
explain select * from user where not exists (select user_name from order_info where user.user_name = order_info.user_name);
至此,我们彻底的了解了 in, exists的区别,下一篇我们讲解下 join的原理,通过join原理,我们可以更加了解SQL查询的底层逻辑