不要再问我 in,exists 走不走索引了

本文探讨了MySQL中in, exists在查询时是否使用索引及其效率问题。实验表明,in查询在某些情况下不会走索引,而exists通常使用内层表的索引。在特定条件下,in查询的效率可能高于exists。文章通过实例分析了in和exists的执行流程,解释了查询优化器如何将in转化为join操作,并提供了关于何时选择in和exists的建议。" 112866378,10534785,R语言拼图排版:调节宽度和高度的艺术,"['R语言', '数据可视化', '图形排版', 'patchwork']
摘要由CSDN通过智能技术生成

前言

最近,有一个业务需求,给我一份数据 A ,把它在数据库 B 中存在,而又比 A 多出的部分算出来。由于数据比较杂乱,我这里简化模型。

然后就会发现,我去,这不就是 not in ,not exists 嘛。

那么问题来了,in, not in , exists , not exists 它们有什么区别,效率如何?

曾经从网上听说,in 和 exists 不会走索引,那么事实真的是这样吗?

带着疑问,我们研究下去。

注意:在说这个问题时,不说明 MySQL 版本的都是耍流氓,我这里用的是 5.7.18 。

用法讲解

为了方便,我们创建两张表 t1 和 t2 。并分别加入一些数据。(id为主键,name为普通索引)

-- t1DROP TABLE IF EXISTS `t1`;CREATE TABLE `t1` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(255) DEFAULT NULL,  `address` varchar(255) DEFAULT NULL,  PRIMARY KEY (`id`),  KEY `idx_t1_name` (`name`(191)) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=1009 DEFAULT CHARSET=utf8mb4;INSERT INTO `t1` VALUES ('1001', '张三', '北京'), ('1002', '李四', '天津'), ('1003', '王五', '北京'), ('1004', '赵六', '河北'), ('1005', '杰克', '河南'), ('1006', '汤姆', '河南'), ('1007', '贝尔', '上海'), ('1008', '孙琪', '北京');-- t2DROP TABLE IF EXISTS `t2`;CREATE TABLE `t2`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,  PRIMARY KEY (`id`) USING BTREE,  INDEX `idx_t2_name`(`name`(191)) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1014 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;INSERT INTO `t2` VALUES (1001, '张三', '北京');INSERT INTO `t2` VALUES (1004, '赵六', '河北');INSERT INTO `t2` VALUES (1005, '杰克', '河南');INSERT INTO `t2` VALUES (1007, '贝尔', '上海');INSERT INTO `t2` VALUES (1008, '孙琪', '北京');INSERT INTO `t2` VALUES (1009, '曹操', '魏国');INSERT INTO `t2` VALUES (1010, '刘备', '蜀国');INSERT INTO `t2` VALUES (1011, '孙权', '吴国');INSERT INTO `t2` VALUES (1012, '诸葛亮', '蜀国');INSERT INTO `t2` VALUES (1013, '典韦', '魏国');

那么,对于当前的问题,就很简单了,用 not in 或者 not exists 都可以把 t1 表中比 t2 表多出的那部分数据给挑出来。(当然,t2 比 t1 多出来的那部分不算)

这里假设用 name 来匹配数据。

select * from t1 where name not in (select name from t2);或者用select * from t1 where not exists (select name from t2 where t1.name=t2.name);

得到的结果都是一样的。

但是,需要注意的是,not in 和 not exists 还是有不同点的。

在使用 not in 的时候,需要保证子查询的匹配字段是非空的。如,此表 t2 中的 name 需要有非空限制。如若不然,就会导致 not in 返回的整个结果集为空。

例如,我在 t2 表中加入一条 name 为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值