一、概述
- from和join均是用于指定需要從哪些表查詢數據,from可以是一個表或多個表,如果是多個表則是生成一個笛卡爾集,會涉及到大量數據。所以通常在涉及到多個表的查詢時,通常通過join來拼接多個表。
- join主要是通過多個表之間的外鍵關聯來進行拼接,注意用于拼接的列需要加上索引,如果沒有則MySQL也會默認加上,不過前提是外鍵列和引用的主鍵列需要是相同的數據類型,如數字類型需要是相同的長度和均是有符号或無符号數,字符串類型長度可以不一樣。以下分析涉及的表結構如下:用戶表t_user和用戶訂單表t_order,在t_order表的user_id列是引用t_user的id列的外鍵。
二、用法分析
FROM
- 将多個表的所有數據行拼成笛卡爾集,故如果表的數據行多時,則數據量很多,造成巨大的磁盤、内存開銷,當然查詢速度也會很慢。
- 如下:xyz2這個用戶其實是沒有訂單的,故from後面跟着這兩個表隻是簡單的進行了:2 * 4=8行,其中用戶表有2行數據,訂單表有4行數據。
LEFT JOIN
- 包含左邊表的所有行和右邊的匹配行,如果左邊表在右邊表不存在關聯數據,則隻包含該行數據,而右邊表相關的數據則是NULL,如下,相對于from,數據行變成了5行,即1*4 1=5
JOIN / INNER JOIN
- join是inner join的簡寫,隻返回匹配表中匹配的數據行,如下:隻返回4行數據。
RIGHT JOIN
- righ join與left join剛好相反,包含右邊表的所有行,如果在左邊表沒有匹配,則相關字段為NULL,由于隻包含4行數據且均與用戶1關聯,故返回4行。
JOIN多次
- 如果包含多個left join(或者多個right join,join等,順序沒有關系),則是前面的left join的結果作為左邊,繼續與後面的left join的表進行拼接,如下創建一個訂單清單條目表t_order_item,并為訂單1創建一個條目:
- 多個left join:返回5行數據,其中第一個left join返回5行數據,然後這5行數據在第二個left join與t_order_item拼表,由于隻插入了一行t_order_item數據,故其他行對應的字段均為null。
- 先left join再right join:第一個left join返回5行數據,由于第二個right join的t_order_item表隻包含一行數據,故最終隻返回一行數據:
三、性能優化
優化方面主要是針對join的優化,因為join本身就是對from的一種優化了。而join的優化主要是從join的列的優化和join的表的左右順序兩個方面來分析。除此之外就是表的反範式設計。
join的列:外鍵索引
- 外鍵約束能夠保證主表和關聯表的數據完整性,但是更新時需要同步更新,所以操作會變慢,即會存在級聯操作。
- 在關聯表創建外鍵約束的語法如下:
- 在主表和關聯表之間,關聯表包含一個映射主表的主鍵(或者其他列,但是必須是包含索引的列,主表用于進行外鍵約束的列必須顯式加上索引)的外鍵,主表的主鍵和關聯表的外鍵需要是相同的數據類型,如數字類型,如果是字符串類型,字符串長度可以不同。該外鍵需要加上索引,對于關聯表的外鍵列,如果沒有顯式加上索引,則MySQL會自動隐式加上索引。如果主表的列與關聯表的外鍵列數據類型不一樣,則無法添加外鍵約束,如下:t_order_item表的order_id為bigint(20),t_order表的order_id為int(11),則無法添加外鍵約束,改成int之後則可以正常添加,并且MySQL添加了一個索引:KEY order_reference (order_id)
inner join的表的左右順序:小表驅動大表
- 在關聯操作中,主表和關聯表的順序對性能影響很重要,特别對于JOIN/INNER JOIN這種匹配關聯來說,因為LEFT/RIGHT JOIN一般是固定的不能調整順序,而INNER JOIN由于是完全匹配,故主表和關聯表的順序可以調換。
- 一般的優化規則是:小表驅動大表,即數據行較少的表在左邊,數據行較多的表在右邊。
- 小表驅動大表的原理:在join當中,是使用左邊表的每一個數據行去掃描右邊的整個表的所有數據行,所以雖然總的匹配次數是相同的,但是如果左邊表數據行很多,則需要加載右邊的整個表很多次,使用小表驅動大表主要是要減少這個次數,即内循環次數,來提高性能。
- 針對以上案例,如果訂單表t_order包含10000行,用戶表t_user包含100行,則用戶表t_user需要在左邊,訂單表t_order需要在右邊,即:
select * from t_user join t_order on t_user.id = t_order.user_id;
- 小表驅動大表的設計隻是我們編寫SQL需要注意的,但是MySQL優化器不一定就完全按照這個順序,MySQL是使用“小結果集”驅動“大結果集”的,即如果SQL語句還包含其他WHERE查詢條件,排序ORDER BY等,則以上順序可能還是反過來的,如果要強制該順序,則可以使用STRAIGHT JOIN來替代INNER JOIN。具體可以參考這位博主的文章:MySQL優化的奇技淫巧之STRAIGHT_JOIN
反範式設計:單表冗餘,不使用JOIN
- MySQL的三範式主要是從減少數據冗餘的角度來規範表的設計,但是這個的曆史背景是以前磁盤資源昂貴的角度出發的,在現代磁盤空間廉價的情況下,進行适當的數據冗餘存儲來避免拼表存在是一種以空間換時間的優化方法,所以進行适當的反範式設計也是一種優化思路。
- 不過反範式設計也要考慮數據的更新問題,因為同一個數據在兩個或多個表中存儲了,故在更新時也要同步更新。