前幾天,小夥伴們在羣裏面討論進行優化join語句,你們都很積極的發言討論,結論是圍繞索引與大小表關係來進行操做,重要的是業務進行綁定。算法
部份內容來源於極客時間的Mysql實戰45講。sql
在Mysql的數據庫中,咱們知道join連接主要使用的有大體三種狀況。數據庫
那這些join咱們須要怎麼使用呢?而且可使用的很好,須要咱們在數據庫裏面嘗試下。微信
該數據表來源於網絡。網絡
-- 建立測試數據庫
CREATE DATABASE join_test CHARSET UTF8;
-- 人員信息表
CREATE TABLE `Persons` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`LastName` char(16) NOT NULL DEFAULT '',
`FirstName` char(16) NOT NULL DEFAULT '',
`Address` varchar(128) NOT NULL DEFAULT '',
`City` varchar(128) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 訂單表
CREATE TABLE `Orders` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`OrderNo` int(11) NOT NULL DEFAULT '0',
`Pid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `Persons` (`LastName`, `FirstName`, `Address`, `City`)
VALUES
('Adams', 'John', 'Oxford Street', 'London'),
('Bush', 'George', 'Fifth Avenue', 'New York'),
('Carter', 'Thomas', 'Changan Street', 'Beijing');
INSERT INTO `Orders` (`OrderNo`, `Pid`)
VALUES (77895, 3), (44678, 3), (22456, 1), (24562, 1), (34764, 65);
複製代碼
建立了兩個字段的關聯關係,而且關聯關係這裏沒有使用索引字段。oop
使用的算法有幾種,一個是Index Nested-Loop join,另外就是Block Nested-Loop Join.性能
關聯表Peoples,與Order表測試
explain select p.* from Persons p
INNER JOIN Orders o on p.id = o.Pid
複製代碼
執行結果圖: 優化
從圖上能夠看出驅動表是Peoples,被驅動表是Order,因爲咱們的關聯關係中,被驅動表沒有索引,因此在執行關聯的時候第二張表要全盤掃描。ui
那執行流程是怎樣的呢?
結果執行的數量是笛卡爾積,進行乘法。
若是join buffer 裏面的數據放不下怎麼辦?
就先取出來一部分驅動表裏面的數據,進行與第二個表對比,循環執行,對比結束後清空buffer中的內容,再處理。
從上面能夠看出,當被驅動表上沒有使用索引的時候會涉及全盤掃描,而且是兩個表都全盤掃描,雖然第一個表內容讀取到內存中能夠加快數據的讀取,可是全盤掃描對於性能屬於一個損耗。
因此咱們須要儘量的創建索引
那麼若是咱們創建索引了呢?
增長索引 索引的名字 與索引的列
CREATE INDEX Pid ON Orders (Pid)
EXPLAIN select p.* from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid;
複製代碼
由於咱們在被驅動的表上增長了索引,因此當咱們須要的是Persons表中的數據時候,能夠利用到索引,執行結果以下。
當兩個表關聯的時候,咱們的People表,還有Order表。選擇People選擇爲驅動表,Order爲被動表,使用On關聯的時候Order 字段上有索引,那麼就會使用該執行算法語句。
算法內容以下:
能夠看到是使用的循環驅動表中的數據而後去被驅動表中查找,利用索引,減小第二個循環的次數。這樣就能加快速度。
從上面能夠看出,在選擇使用join的時候,必定要避免sql語句將關聯的第二個上使用join語句,咱們能夠每次將本身執行的語句加上explain簡單的看下sql執行計劃,在優化咱們的sql語句。
還有做爲驅動表的數據儘量少,循環的數據就不多了。
這就有咱們前面所說的小表做爲驅動表,大表加索引。這個概念。
上面咱們說了使用的兩個算法,那麼咱們在執行過程當中會遇到哪些呢?
重點強調,咱們的語句都每次使用explain來查看輸出
inner join 與join語句執行結果是一致的,因此在看執行結果,咱們沒必要要關注某個點。
在使用inner join 的時候,以哪一個左表仍是右表做爲依賴表都是存在可能的,因此咱們可使用straight_join來強制使用某個表做爲依賴表,而且在使用inner join語句的時候該straight_join 也是一個優化的方式。
強制採用某個表做爲依賴表。
// 注意當咱們使用join語句,須要查詢第二個表數據的時候,若是咱們的where 條件中沒有增長 篩選條件可能會致使使用Block Nested-Loop Join
EXPLAIN select p.id,o.OrderNo from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid;
複製代碼
那麼這種狀況下怎麼優化的呢?
從圖上能夠看出來,咱們的表二沒有走索引,致使咱們數據進行全盤的掃描。
在每個數據庫的表上,咱們都瞭解會有主鍵索引,那麼咱們是否能夠根據主鍵索引來排除呢?
咱們經過sql來看。
當OrderNo上沒有索引的時候
EXPLAIN select p.id,o.OrderNo from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid
where o.OrderNo > 30000
複製代碼
走的是全盤掃描,若是咱們在OrderNo上加上索引呢?
增長普通索引
CREATE INDEX Pid ON Orders (Pid)
//在我建立索引的時候,有時候條件語句是能夠用上索引的,有的時候是用不上的。因爲數據量過小的緣由致使部分索引使用補上的狀況。在這裏根據不一樣的字段內容是能使用上索引的。
EXPLAIN select p.id,o.OrderNo from Persons p
STRAIGHT_JOIN Orders o on p.id = o.Pid
where o.Pid > 3
複製代碼
因此咱們在使用語句的時候須要多多關注索引的使用,關於Tree索引,咱們下次再聊。
從上面能夠看到,使用索引能幫助咱們提升不少,可是寫入的SQL中能不能執行使用索引,還跟語句的構成有關。
儘可能在寫出來的sql都須要執行下explain 檢查下執行情況,知道sql的執行結果,這樣咱們能真正的寫出來好的join語句。
關於使用join,建議使用left join或者right join 提升效率。具體分析下次再聊。
·END·
路雖遠,行則必至
本文原發於 同名微信公衆號「胖琪的升級之路」,回覆「1024」你懂得,給個讚唄。
微信ID:YoungRUIQ