Mysql中in和exists的區(qū)別?&?not?in、not?exists、left?join的相互轉(zhuǎn)換問題
數(shù)據(jù)準備
-- 建表 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 '學(xué)校', 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 '學(xué)校', 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); -- 添數(shù)據(jù) INSERT INTO lelele.xin_stu_t_bak (id,relation_id,student_name,student_age,school) VALUES (1,NULL,'尤仁義1',11,'徐州中學(xué)'), (2,1,'尤仁義2',12,'徐州中學(xué)'), (3,NULL,'朱有理1',11,'徐州中學(xué)'), (4,2,'朱有理2',12,'徐州中學(xué)'), (5,2,'朱有理3',13,'徐州中學(xué)'), (6,3,'宋昆明1',11,'徐州中學(xué)'), (7,3,'宋昆明2',12,'徐州中學(xué)'), (8,14,'宋昆明3',13,'徐州中學(xué)'); INSERT INTO lelele.xin_teach_t_bak (id,teacher_name,teacher_age,school) VALUES (1,'王翠花1',31,'徐州中學(xué)'), (2,'王翠花2',31,'徐州中學(xué)'), (3,'王翠花3',33,'徐州中學(xué)'), (4,'王翠花4',34,'徐州中學(xué)'), (5,'王翠花5',35,'徐州中學(xué)'), (1,'王翠花1',31,'徐州中學(xué)'), (1,'王翠花1',31,'徐州中學(xué)'), (2,'王翠花2',31,'徐州中學(xué)'), (6,'王翠花6',31,'徐州中學(xué)'), (7,'王翠花7',31,'徐州中學(xué)'); INSERT INTO lelele.xin_teach_t_bak (id,teacher_name,teacher_age,school) VALUES (8,'王翠花8',33,'徐州中學(xué)'), (9,'王翠花9',34,'徐州中學(xué)'), (10,'王翠花10',35,'徐州中學(xué)'), (11,'王翠花11',31,'徐州中學(xué)'), (12,'王翠花12',31,'徐州中學(xué)'), (13,'王翠花13',31,'徐州中學(xué)');
1. in 介紹
1.1 in中數(shù)據(jù)量的限制
在oracle中,int中數(shù)據(jù)集的大小超過1000會報錯;
在mysql中,超過1000不會報錯,但也是有數(shù)據(jù)量限制的,應(yīng)該是4mb,但不建議數(shù)據(jù)集超過1000,
因為in是可以走索引的,但in中數(shù)據(jù)量過大索引就會失效
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的執(zhí)行邏輯
- 當前的in子查詢是B表驅(qū)動A表
- mysql先將B表的數(shù)據(jù)一把查出來至于內(nèi)存中
- 遍歷B表的數(shù)據(jù),再去查A表(每次遍歷都是一次連接交互,這里會耗資源)
- 假設(shè)B有100000條記錄,A有10條記錄,會交互100000次數(shù)據(jù)庫;再假設(shè)B有10條記錄,A有100000記錄,只會發(fā)生10次交互。
結(jié)論: in是先進行子查詢,再與外面的數(shù)據(jù)進行循環(huán)遍歷,屬于子查詢的結(jié)果集驅(qū)動外面的結(jié)果集,
當in子查詢的結(jié)果集較小時,就形成了小表驅(qū)動大表,而兩張表的驅(qū)動就是一張表的行數(shù)據(jù)去循環(huán)關(guān)聯(lián)另一張表,
關(guān)聯(lián)次數(shù)越少越好,所以小表去查詢大表,次數(shù)更少,性能更高
in()適合B表比A表數(shù)據(jù)小的情況
2. exists介紹
2.1 exists + not exists 是全量數(shù)據(jù)
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 是全量數(shù)據(jù),這點與in不同
2.2 exists的執(zhí)行邏輯
- 當前exists查詢是A表驅(qū)動B表
- 與in不同,exists將A的紀錄數(shù)查詢到內(nèi)存,因此A表的記錄數(shù)決定了數(shù)據(jù)庫的交互次數(shù)
- 假設(shè)A有10000條記錄,B有10條記錄,數(shù)據(jù)庫交互次數(shù)為10000;假設(shè)A有10條,B有10000條,數(shù)據(jù)庫交互次數(shù)為10。
結(jié)論:exists理論上就是boolean值,關(guān)聯(lián)后查詢到有值則是true數(shù)據(jù)留下,關(guān)聯(lián)后查詢沒有值則是false數(shù)據(jù)舍棄;exists適合B表數(shù)據(jù)量大,A表數(shù)據(jù)量小的情況,與in相反
3. 小表驅(qū)動大表的好處
我們來看下面兩個循環(huán):
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中,我們都知道上述的兩個循環(huán)的時間復(fù)雜度都是一樣的;
但在數(shù)據(jù)庫中則是有區(qū)別的,
首先第一層循環(huán),數(shù)據(jù)庫只做一次交互一把將數(shù)據(jù)查出到緩存中,
而第二層循環(huán)的數(shù)據(jù)庫交互次數(shù)決定于第一層循環(huán)數(shù)據(jù)量的大小。
對于數(shù)據(jù)庫而言,交互次數(shù)越多越耗費資源,一次交互涉及了“連接-查找-斷開”這些操作,是相當耗費資源的。
使用in時,B表驅(qū)動A
使用exists時,A表驅(qū)動B
所以我們寫sql時應(yīng)當遵循“小表驅(qū)動大表“的原則
4. in、not in、exists、not exists是否可以走索引(都可以)
in可以走索引,但數(shù)據(jù)量過大時就不走索引了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語句相互轉(zhuǎn)換(必須在表關(guān)聯(lián)時,否則并不等同)
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;
到此這篇關(guān)于Mysql中in和exists的區(qū)別 & not in、not exists、left join的相互轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)Mysql中in和exists區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- sql語句優(yōu)化之用EXISTS替代IN、用NOT EXISTS替代NOT IN的語句
- MySQL: mysql is not running but lock exists 的解決方法
- mysql insert if not exists防止插入重復(fù)記錄的方法
- UCenter info: MySQL Query Error SQL:SELECT value FROM [Table]vars WHERE noteexists
- mysql not in、left join、IS NULL、NOT EXISTS 效率問題記錄
- sql not in 與not exists使用中的細微差別
- SQL中NOT IN與NOT EXISTS不等價的問題
相關(guān)文章
MySQL中having和where的區(qū)別及應(yīng)用詳解
這篇文章主要給大家詳細介紹了MySQL中having和where的區(qū)別以及他們的使用方法,文中有相關(guān)的代碼示例,具有一定的參考價值,需要的朋友可以參考下2023-06-06mysql中GROUP_CONCAT函數(shù)使用技巧及問題詳解
這篇文章主要給大家介紹了關(guān)于mysql中GROUP_CONCAT函數(shù)使用技巧及問題的相關(guān)資料,GROUP_CONCAT是MySQL中的一個聚合函數(shù),它用于將多行數(shù)據(jù)按照指定的順序連接成一個字符串并返回結(jié)果,需要的朋友可以參考下2023-11-11MySQL中LIKE?BINARY和LIKE模糊查詢實例代碼
通常在實際應(yīng)用中,會涉及到模糊查詢的需求,下面這篇文章主要給大家介紹了關(guān)于MySQL中LIKE?BINARY和LIKE模糊查詢的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-11-11解決hibernate+mysql寫入數(shù)據(jù)庫亂碼
初次沒習(xí)hibernate,其中遇到問題在網(wǎng)上找的答案與大家共同分享!2009-07-07