mysql left join的坑和優化經驗

2022-09-24 04:09:10 字數 2061 閱讀 5000

參考文章:

create table classes (

`id` int(11) not null primary key,

`name` varchar(32) not null

)insert into classes (`id`, `name`) values

(1, '一班'),

(2, '二班'),

(3, '三班'),

(4, '四班')

create table students (

`id` int(11) not null primary key auto_increment,

`class_id` int(11) not null,

`name` varchar(32),

`gender` varchar(1)

)insert into students(

`class_id`,

`name`,

`gender`

)values

(1, '小明', 'm'),

(1, '小紅', 'f'),

(1, '小軍', 'm'),

(1, '小公尺', 'f'),

(2, '小白', 'm'),

(2, '小兵', 'f'),

(2, '小林', 'f'),

(3, '小新', 'f'),

(3, '小王', 'm'),

(3, '小麗', 'f')

mysql 對於left join的採用類似巢狀迴圈的方式來進行從處理,以下面的語句為例:

select * from lt left join rt on p1(lt,rt)) where p2(lt,rt)
其中p1是on過濾條件,缺失則認為是true,p2是where過濾條件,缺失也認為是true,該語句的執行邏輯可以描述為:

for each row lt in lt 

b=true;// lt在rt中有對應的行

} if (!b)

}}

當然,實際情況中mysql會使用buffer的方式進行優化,減少行比較次數,不過這不影響關鍵的執行流程,不在本文討論範圍之內。

從這個偽**中,我們可以看出兩點:

下面展開兩個需求的錯誤語句的執行結果和錯誤原因:

需求1

需求2

需求1由於在where條件中對右表限制,導致資料缺失(四班應該有個為0的結果)

正確的slq應該為

select c.name, count(s.name) as num 

from classes c left join students s

on (s.class_id = c.id and s.gender = 'f')

group by c.name

需求2由於在on條件中對左表限制,導致資料多餘(其他班的結果也出來了,還是錯的)

通過上面的問題現象和分析,可以得出了結論:在left join語句中,左表過濾必須放where條件中,右表過濾必須放on條件中,這樣結果才能不多不少,剛剛好。

sql 看似簡單,其實也有很多細節原理在裡面,乙個小小的混淆就會造成結果與預期不符,所以平時要注意這些細節原理,避免關鍵時候出錯。

根據經驗。我更喜歡直接用where組合成為虛擬表,這樣虛擬錶能直接使用到索引,也能較少笛卡爾乘積,使得大表的查詢效率大大提高,也絕不會發生錯誤。

優化後的sql為

select c.name, count(s.name) as num 

from classes c left join (select * from students s where s.gender = 'f') as s

on s.class_id = c.id

group by c.name

MySQL left join 避坑指南

這裡我先給出乙個場景,並丟擲兩個問題,如果你都能答對那這篇文章就不用看了。那麼現在有兩個需求 找出每個班級的名稱及其對應的女同學數量 找出一班的同學總數 對於需求1,大多數人不假思索就能想出如下兩種sql寫法 正確 select c.name,count s.name as num from cla...

mysql left join實際遇到的問題

sql1 select a.b.from zf sys user a left join select from zf user exam info where user id in 1,2,3 and exam id 1 b on a.id b.user id where a.id in 1,2,...

MYSQl left join聯合查詢效率分析

user表 id name 1 libk 2 zyfon 3 daodao user action表 user id action 1 jump 1 kick 1 jump 2 run 4 swim sql select id,name,action from user as u left join...