問題描述
昨天在面試中遇到了這樣一個問題:
假如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表的數據,最終結果: