亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MySQL之join查詢優(yōu)化方式

 更新時(shí)間:2023年03月12日 15:49:49   作者:布道  
這篇文章主要介紹了MySQL之join查詢優(yōu)化方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

MySQL join查詢優(yōu)化

在日常的開發(fā)中,我們經(jīng)常遇到這樣情況:select * from TableA  inner join TableB...它響應(yīng)速度一直很快的,隨著數(shù)據(jù)的增長(zhǎng),突然有一天開始很慢了。那該怎么破?

對(duì),驅(qū)動(dòng)表是突破口,

1. 那什么是驅(qū)動(dòng)表呢?

  • 指定了聯(lián)接條件時(shí),滿足查詢條件的記錄行數(shù)少的表為驅(qū)動(dòng)表
  • 未指定聯(lián)接條件時(shí),行數(shù)少的表為驅(qū)動(dòng)表(Important!)

如果你搞不清楚該讓誰做驅(qū)動(dòng)表、誰 join 誰,就別指定誰 left/right join 誰了,請(qǐng)交給 MySQL優(yōu)化器 運(yùn)行時(shí)決定吧。

2. 復(fù)雜的sql怎么識(shí)別驅(qū)動(dòng)表呢?

按經(jīng)驗(yàn)談,使用EXPLAIN, 第一行出現(xiàn)的表就是驅(qū)動(dòng)表。

3. 關(guān)聯(lián)查詢?cè)硎窃鯓拥模?/h3>

MySQL 表關(guān)聯(lián)的算法是 Nest Loop Join,是通過驅(qū)動(dòng)表的結(jié)果集作為循環(huán)基礎(chǔ)數(shù)據(jù),然后一條一條地通過該結(jié)果集中的數(shù)據(jù)作為過濾條件到下一個(gè)表中查詢數(shù)據(jù),然后合并結(jié)果。

//例: user表10000條數(shù)據(jù),class表20條數(shù)據(jù)
select * from user u left join class c u.userid=c.userid

上面sql的后果就是需要用user表循環(huán)10000次才能查詢出來,而如果用class表驅(qū)動(dòng)user表則只需要循環(huán)20次就能查詢出來。

4. 該如如何優(yōu)化?

優(yōu)化的目標(biāo)是盡可能減少JOIN中Nested Loop的循環(huán)次數(shù),以此保證:永遠(yuǎn)用小結(jié)果集驅(qū)動(dòng)大結(jié)果集。

排序的字段也有影響,有條原則:對(duì)驅(qū)動(dòng)表可以直接排序,對(duì)非驅(qū)動(dòng)表(的字段排序)需要對(duì)循環(huán)查詢的合并結(jié)果(臨時(shí)表)進(jìn)行排序!

5. 實(shí)例

explain select * from user u left join class c on u.userid=c.userid INNER JOIN subject s on c.subjectId=s.id?
?WHERE 1=1 ORDER BY u.create_time DESC limit 0,10

夠復(fù)雜吧。假如,user表有千萬級(jí)記錄,class表要少得多,從執(zhí)行計(jì)劃的得知驅(qū)動(dòng)表(數(shù)據(jù)到千萬級(jí))。由于動(dòng)用了“LEFT JOIN”,所以相當(dāng)于已經(jīng)指定了驅(qū)動(dòng)表。

如何優(yōu)化?

//優(yōu)化第一步:LEFT JOIN改為JOIN,對(duì),直接 join!
explain select * from user u join class c on u.userid=c.userid INNER JOIN subject s on c.subjectId=s.id?
?WHERE 1=1 ORDER BY u.create_time DESC limit 0,10
//優(yōu)化第二步:從上面執(zhí)行計(jì)劃得知, 有Using temporary(臨時(shí)表);Using filesort,解決方法是調(diào)整排序字段(借助前面講過排序的原則)
explain select * from user u join class c on u.userid=c.userid INNER JOIN subject s on c.subjectId=s.id?
?WHERE 1=1 ORDER BY c.id DESC limit 0,10

總之,sql優(yōu)化中explain工具是非常重要的武器。

MySQL優(yōu)化(關(guān)聯(lián)查詢優(yōu)化)

準(zhǔn)備數(shù)據(jù)

#分類
CREATE TABLE IF NOT EXISTS `class` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
);
#圖書
CREATE TABLE IF NOT EXISTS `book` (
`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`bookid`)
);
 
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
 
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

left join左外連接

看這個(gè)分析結(jié)果發(fā)現(xiàn):在 class 表上添加的索引起的作用不大。

結(jié)論: 

- **小表驅(qū)動(dòng)大表**

  • - 小表:相對(duì)來說記錄較少的表
  • - 大表:相對(duì)來說記錄較多的表

- 驅(qū)動(dòng)方式識(shí)別

  • left join:左邊驅(qū)動(dòng)右邊(此時(shí)把小表放在左邊)
  • right join:右邊驅(qū)動(dòng)左邊(此時(shí)把小表放在右邊)

- 加索引的方式:通常建議在大表(被驅(qū)動(dòng))的表加索引,效率提升更明顯。

- 原因:

  • 原因1:被驅(qū)動(dòng)表加了索引之后,收益更大。從 ALL -> ref
  • 原因2:外連接首先讀取驅(qū)動(dòng)表的全部數(shù)據(jù),被驅(qū)動(dòng)只讀取滿足連接條件的數(shù)據(jù)。

inner join:MySQL會(huì)自動(dòng)根據(jù)表中的數(shù)據(jù)選擇驅(qū)動(dòng)表

小結(jié):

- 保證被驅(qū)動(dòng)表的 join 字段被索引。join 字段就是作為連接條件的字段。

- left join 時(shí),選擇小表作為驅(qū)動(dòng)表(放左邊),大表作為被驅(qū)動(dòng)表(放右邊)

- inner join 時(shí),mysql 會(huì)自動(dòng)將小結(jié)果集的表選為驅(qū)動(dòng)表。

- 子查詢盡量不要放在被驅(qū)動(dòng)表,衍生表建不了索引

- 能夠直接多表關(guān)聯(lián)的盡量直接關(guān)聯(lián),不用子查詢

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論