Mysql中in和exists的區(qū)別?&?not?in、not?exists、left?join的相互轉(zhuǎn)換問題
數(shù)據(jù)準(zhǔn)備
-- 建表 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會(huì)報(bào)錯(cuò);
在mysql中,超過1000不會(huì)報(bào)錯(cuò),但也是有數(shù)據(jù)量限制的,應(yīng)該是4mb,但不建議數(shù)據(jù)集超過1000,
因?yàn)閕n是可以走索引的,但in中數(shù)據(jù)量過大索引就會(huì)失效
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í)行邏輯
- 當(dāng)前的in子查詢是B表驅(qū)動(dòng)A表
- mysql先將B表的數(shù)據(jù)一把查出來至于內(nèi)存中
- 遍歷B表的數(shù)據(jù),再去查A表(每次遍歷都是一次連接交互,這里會(huì)耗資源)
- 假設(shè)B有100000條記錄,A有10條記錄,會(huì)交互100000次數(shù)據(jù)庫;再假設(shè)B有10條記錄,A有100000記錄,只會(huì)發(fā)生10次交互。
結(jié)論: in是先進(jìn)行子查詢,再與外面的數(shù)據(jù)進(jìn)行循環(huán)遍歷,屬于子查詢的結(jié)果集驅(qū)動(dòng)外面的結(jié)果集,
當(dāng)in子查詢的結(jié)果集較小時(shí),就形成了小表驅(qū)動(dòng)大表,而兩張表的驅(qū)動(dòng)就是一張表的行數(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ù),這點(diǎn)與in不同
2.2 exists的執(zhí)行邏輯
- 當(dāng)前exists查詢是A表驅(qū)動(dòng)B表
- 與in不同,exists將A的紀(jì)錄數(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ū)動(dòng)大表的好處
我們來看下面兩個(gè)循環(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中,我們都知道上述的兩個(gè)循環(huán)的時(shí)間復(fù)雜度都是一樣的;
但在數(shù)據(jù)庫中則是有區(qū)別的,
首先第一層循環(huán),數(shù)據(jù)庫只做一次交互一把將數(shù)據(jù)查出到緩存中,
而第二層循環(huán)的數(shù)據(jù)庫交互次數(shù)決定于第一層循環(huán)數(shù)據(jù)量的大小。
對于數(shù)據(jù)庫而言,交互次數(shù)越多越耗費(fèi)資源,一次交互涉及了“連接-查找-斷開”這些操作,是相當(dāng)耗費(fèi)資源的。
使用in時(shí),B表驅(qū)動(dòng)A
使用exists時(shí),A表驅(qū)動(dòng)B
所以我們寫sql時(shí)應(yīng)當(dāng)遵循“小表驅(qū)動(dòng)大表“的原則
4. in、not in、exists、not exists是否可以走索引(都可以)
in可以走索引,但數(shù)據(jù)量過大時(shí)就不走索引了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)時(shí),否則并不等同)
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)文章希望大家以后多多支持腳本之家!
- 淺談mysql雙層not exists查詢執(zhí)行流程
- mysql exists與not exists實(shí)例詳解
- mysql not in、left join、IS NULL、NOT EXISTS 效率問題記錄
- UCenter info: MySQL Query Error SQL:SELECT value FROM [Table]vars WHERE noteexists
- mysql insert if not exists防止插入重復(fù)記錄的方法
- MySQL: mysql is not running but lock exists 的解決方法
- 淺談mysql的not exists走不走索引
相關(guān)文章
MySQ實(shí)現(xiàn)XA事務(wù)的具體使用
XA事務(wù)是一種分布式事務(wù)處理協(xié)議,本文主要介紹了MySQ實(shí)現(xiàn)XA事務(wù)的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07關(guān)于MySQL外鍵的簡單學(xué)習(xí)教程
這篇文章主要介紹了關(guān)于MySQL外鍵的簡單學(xué)習(xí)教程,對InnoDB引擎下的外鍵約束做了簡潔的講解,需要的朋友可以參考下2015-11-11mysql數(shù)據(jù)庫操作_高手進(jìn)階常用的sql命令語句大全
mysql數(shù)據(jù)庫操作sql命令語句大全:三表連表查詢、更新時(shí)批量替換字段部分字符、判斷某一張表是否存在、自動(dòng)增長恢復(fù)從1開始、查詢重復(fù)記錄、更新時(shí)字段值等于原值加上一個(gè)字符串、更新某字段為隨機(jī)值、復(fù)制表數(shù)據(jù)到另一個(gè)表、創(chuàng)建表時(shí)拷貝其他表的數(shù)據(jù)和結(jié)構(gòu)...2022-11-11一文帶你學(xué)會(huì)MySQL的select語句
在MySQL中可以使用SELECT語句來查詢數(shù)據(jù),查詢數(shù)據(jù)是指從數(shù)據(jù)庫中根據(jù)需求,使用不同的查詢方式來獲取不同的數(shù)據(jù),是使用頻率最高、最重要的操作,下面這篇文章主要給大家介紹了關(guān)于MySQL中select語句的相關(guān)資料,需要的朋友可以參考下2022-11-11mysql格式化小數(shù)保留小數(shù)點(diǎn)后兩位(小數(shù)點(diǎn)格式化)
今天遇到一個(gè)問題,格式化浮點(diǎn)數(shù)的問題,用format(col,2)保留兩位小數(shù)點(diǎn),出現(xiàn)一個(gè)問題,例如下面的語句,后面我們給出解決方法2013-12-12