问题描述
昨天在面试中遇到了这样一个问题:
假如aa表中存在XX字段,bb表中存在XX字段,要求使用最快的sql找出存在aa表中但不存在bb表中的数据,请说明原因为什么认为它最快
问题分析
根据问题,立马回想起了以前的一个项目,这不就是找新增数据嘛,见下图:
绿色就代表新增数据了,红色代表join数据,很显然题中是只需要绿色部分的新增数据即可;
然而left join
会查询出红色+绿色;而inner join
只能查询出红色;
让left join结果 - inner join结果
就好了,这是最原始的想法,也是最笨的思路,显然要丢弃
解决方案
既然打算实验,那就先创建两张表吧!
部门表
-- ----------------------------
-- Table structure for department
-- ----------------------------
DROP TABLE IF EXISTS `department`;
CREATE TABLE `department` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '表ID字段',
`dept` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of department
-- ----------------------------
INSERT INTO `department` VALUES (1, '开发部');
INSERT INTO `department` VALUES (2, '测试部');
INSERT INTO `department` VALUES (3, '其他部');
INSERT INTO `department` VALUES (4, '数据部');
新部门表
-- ----------------------------
-- Table structure for new_department
-- ----------------------------
DROP TABLE IF EXISTS `new_department`;
CREATE TABLE `new_department` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`dept` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部门',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of new_department
-- ----------------------------
INSERT INTO `new_department` VALUES (1, '开发部');
INSERT INTO `new_department` VALUES (2, '测试部');
INSERT INTO `new_department` VALUES (3, '财务部');
INSERT INTO `new_department` VALUES (4, '运营部');
INSERT INTO `new_department` VALUES (5, '市场部');
INSERT INTO `new_department` VALUES (6, '数据部');
说明:为了简化,以下用a表代表new_department; b表代表department
方案一
-- 1、找到b表中所有的dept
-- 2、找到a表中所有的dept
-- 3、使用not in进行排除重复数据
SELECT
*
FROM
new_department a
WHERE
dept NOT IN ( SELECT dept FROM department b);
效率最低,不做解释了
方案二
-- 1、a表左连接b表,可以查出所有部门信息(可以查看效果)
-- 2、判断条件:b表的dept为空,即能查询出新增数据
SELECT
*
FROM
new_department a
LEFT JOIN department b ON a.dept = b.dept
WHERE
b.dept IS NULL;
左连接效果:
效率比not in要快上一些,至少两条语句都是简单查询
方案三
-- sql执行顺序
-- from => where => group by => having => order => select
-- 1、统计a表和b表连接的行数,连接字段:dept
-- 2、子查询的行数为0,即能查询出新增数据
SELECT
*
FROM
new_department a
WHERE
( SELECT count( 1 ) FROM department b WHERE a.dept = b.dept ) = 0;
使用数字比较,也比not in要快,至于方案二和方案三谁快,就需要进行大量试验了
方案三分析
参考了https://zhidao.baidu.com/question/509144661.html中第二条评论
先来查看一下a表和b表的所有数据吧
department表数据(b表)
SELECT * FROM new_department;
new_department表数据(a表)
SELECT * FROM department;
select * from new_department
是执行a表
-
当执行“dept=开发部”时 ,执行
select count(1) from department b where a.dept = b.dept
,因为a表和b表都有"开发部",结果不等于0,所以运行结果没有第一行“dept=开发部”; -
当执行“dept=测试部”时 ,执行
select count(1) from department b where a.dept = b.dept
,因为a表和b表都有"测试部",结果不等于0,所以运行结果没有第二行“dept=测试部”; -
当执行“dept=财务部”时 ,执行
select count(1) from department b where a.dept = b.dept
,因为a表有"财务部"而b表没有"财务部",结果等于0 ,符合条件,所以被查询出来了; -
其余依次类推,因此可以在a表中排除b表的数据,最终结果: