Mysql Join文法解析與效能分析

來源:互聯網
上載者:User

標籤:

一.Join文法概述

join 用於多表中欄位之間的聯絡,文法如下:

... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona

table1:左表;table2:右表。

JOIN 按照功能大致分為如下三類:

INNER JOIN(內串連,或等值串連):取得兩個表中存在串連匹配關係的記錄。

LEFT JOIN(左串連):取得左表(table1)完全記錄,即是右表(table2)並無對應匹配記錄。

RIGHT JOIN(右串連):與 LEFT JOIN 相反,取得右表(table2)完全記錄,即是左表(table1)並無匹配對應記錄。

注意:mysql不支援Full join,不過可以通過UNION 關鍵字來合并 LEFT JOIN 與 RIGHT JOIN來類比FULL join.

接下來給出一個列子用於解釋下面幾種分類。如下兩個表(A,B)

mysql> select A.id,A.name,B.name from A,B where A.id=B.id;+----+-----------+-------------+| id | name       | name             |+----+-----------+-------------+|  1 | Pirate       | Rutabaga      ||  2 | Monkey    | Pirate            ||  3 | Ninja         | Darth Vader ||  4 | Spaghetti  | Ninja             |+----+-----------+-------------+4 rows in set (0.00 sec)
二.Inner join

內串連,也叫等值串連,inner join產生同時符合A和B的一組資料。

mysql> select * from A inner join B on A.name = B.name;+----+--------+----+--------+| id | name   | id | name   |+----+--------+----+--------+|  1 | Pirate |  2 | Pirate ||  3 | Ninja  |  4 | Ninja  |+----+--------+----+--------+

三.Left join
mysql> select * from A left join B on A.name = B.name;#或者:select * from A left outer join B on A.name = B.name;+----+-----------+------+--------+| id | name      | id   | name   |+----+-----------+------+--------+|  1 | Pirate    |    2 | Pirate ||  2 | Monkey    | NULL | NULL   ||  3 | Ninja     |    4 | Ninja  ||  4 | Spaghetti | NULL | NULL   |+----+-----------+------+--------+4 rows in set (0.00 sec)

left join,(或left outer join:在Mysql中兩者等價,推薦使用left join.)左串連從左表(A)產生一套完整的記錄,與匹配的記錄(右表(B)) .如果沒有匹配,右側將包含null。

如果想只從左表(A)中產生一套記錄,但不包含右表(B)的記錄,可以通過設定where語句來執行,如下:

mysql> select * from A left join B on A.name=B.name where A.id is null or B.id is null;+----+-----------+------+------+| id | name      | id   | name |+----+-----------+------+------+|  2 | Monkey    | NULL | NULL ||  4 | Spaghetti | NULL | NULL |+----+-----------+------+------+2 rows in set (0.00 sec)

同理,還可以類比inner join. 如下:

mysql> select * from A left join B on A.name=B.name where A.id is not null and B.id is not null;+----+--------+------+--------+| id | name   | id   | name   |+----+--------+------+--------+|  1 | Pirate |    2 | Pirate ||  3 | Ninja  |    4 | Ninja  |+----+--------+------+--------+2 rows in set (0.00 sec)

求差集:

根據上面的例子可以求差集,如下:

SELECT * FROM A LEFT JOIN B ON A.name = B.nameWHERE B.id IS NULLunionSELECT * FROM A right JOIN B ON A.name = B.nameWHERE A.id IS NULL;# 結果    +------+-----------+------+-------------+| id   | name      | id   | name        |+------+-----------+------+-------------+|    2 | Monkey    | NULL | NULL        ||    4 | Spaghetti | NULL | NULL        || NULL | NULL      |    1 | Rutabaga    || NULL | NULL      |    3 | Darth Vader |+------+-----------+------+-------------+

四.Right join
mysql> select * from A right join B on A.name = B.name;+------+--------+----+-------------+| id   | name   | id | name        |+------+--------+----+-------------+| NULL | NULL   |  1 | Rutabaga    ||    1 | Pirate |  2 | Pirate      || NULL | NULL   |  3 | Darth Vader ||    3 | Ninja  |  4 | Ninja       |+------+--------+----+-------------+4 rows in set (0.00 sec)

同left join。

五.Cross join

cross join:交叉串連,得到的結果是兩個表的乘積,即笛卡爾積

笛卡爾(Descartes)乘積又叫直積。假設集合A={a,b},集合B={0,1,2},則兩個集合的笛卡爾積為{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。可以擴充到多個集合的情況。類似的例子有,如果A表示某學校學生的集合,B表示該學校所有課程的集合,則A與B的笛卡爾積表示所有可能的選課情況。

mysql> select * from A cross join B;+----+-----------+----+-------------+| id | name      | id | name        |+----+-----------+----+-------------+|  1 | Pirate    |  1 | Rutabaga    ||  2 | Monkey    |  1 | Rutabaga    ||  3 | Ninja     |  1 | Rutabaga    ||  4 | Spaghetti |  1 | Rutabaga    ||  1 | Pirate    |  2 | Pirate      ||  2 | Monkey    |  2 | Pirate      ||  3 | Ninja     |  2 | Pirate      ||  4 | Spaghetti |  2 | Pirate      ||  1 | Pirate    |  3 | Darth Vader ||  2 | Monkey    |  3 | Darth Vader ||  3 | Ninja     |  3 | Darth Vader ||  4 | Spaghetti |  3 | Darth Vader ||  1 | Pirate    |  4 | Ninja       ||  2 | Monkey    |  4 | Ninja       ||  3 | Ninja     |  4 | Ninja       ||  4 | Spaghetti |  4 | Ninja       |+----+-----------+----+-------------+16 rows in set (0.00 sec)#再執行:mysql> select * from A inner join B; 試一試#在執行mysql> select * from A cross join B on A.name = B.name; 試一試

實際上,在 MySQL 中(僅限於 MySQL) CROSS JOIN 與 INNER JOIN 的表現是一樣的,在不指定 ON 條件得到的結果都是笛卡爾積,反之取得兩個表完全符合的結果。
INNER JOIN 與 CROSS JOIN 可以省略 INNER 或 CROSS 關鍵字,因此下面的 SQL 效果是一樣的:

... FROM table1 INNER JOIN table2... FROM table1 CROSS JOIN table2... FROM table1 JOIN table2
六.Full join
mysql> select * from A left join B on B.name = A.name     -> union     -> select * from A right join B on B.name = A.name;+------+-----------+------+-------------+| id   | name      | id   | name        |+------+-----------+------+-------------+|    1 | Pirate    |    2 | Pirate      ||    2 | Monkey    | NULL | NULL        ||    3 | Ninja     |    4 | Ninja       ||    4 | Spaghetti | NULL | NULL        || NULL | NULL      |    1 | Rutabaga    || NULL | NULL      |    3 | Darth Vader |+------+-----------+------+-------------+6 rows in set (0.00 sec)

全串連產生的所有記錄(雙方匹配記錄)在表A和表B。如果沒有匹配,則對面將包含null。

七.效能最佳化1.顯示(explicit) inner join VS 隱式(implicit) inner join

如:

select * fromtable a inner join table bon a.id = b.id;

VS

select a.*, b.*from table a, table bwhere a.id = b.id;

我在資料庫中比較(10w資料)得之,它們用時幾乎相同,第一個是顯示的inner join,後一個是隱式的inner join。

參照:Explicit vs implicit SQL joins

2.left join/right join VS inner join

盡量用inner join.避免 LEFT JOIN 和 NULL.

在使用left join(或right join)時,應該清楚的知道以下幾點:

(1). on與 where的執行順序

ON 條件(“A LEFT JOIN B ON 條件運算式”中的ON)用來決定如何從 B 表中檢索資料行。如果 B 表中沒有任何一行資料匹配 ON 的條件,將會額外產生一行所有列為 NULL 的資料,在匹配階段 WHERE 子句的條件都不會被使用。僅在匹配階段完成以後,WHERE 子句條件才會被使用。它將從匹配階段產生的資料中檢索過濾。

所以我們要注意:在使用Left (right) join的時候,一定要在先給出儘可能多的匹配滿足條件,減少Where的執行。如:

PASS

select * from Ainner join B on B.name = A.nameleft join C on C.name = B.nameleft join D on D.id = C.idwhere C.status>1 and D.status=1;

Great

select * from Ainner join B on B.name = A.nameleft join C on C.name = B.name and C.status>1left join D on D.id = C.id and D.status=1

從上面例子可以看出,儘可能滿足ON的條件,而少用Where的條件。從執行效能來看第二個顯然更加省時。

(2).注意ON 子句和 WHERE 子句的不同

如作者舉了一個列子:

mysql> SELECT * FROM product LEFT JOIN product_details       ON (product.id = product_details.id)       AND product_details.id=2;+----+--------+------+--------+-------+| id | amount | id   | weight | exist |+----+--------+------+--------+-------+|  1 |    100 | NULL |   NULL |  NULL ||  2 |    200 |    2 |     22 |     0 ||  3 |    300 | NULL |   NULL |  NULL ||  4 |    400 | NULL |   NULL |  NULL |+----+--------+------+--------+-------+4 rows in set (0.00 sec) mysql> SELECT * FROM product LEFT JOIN product_details       ON (product.id = product_details.id)       WHERE product_details.id=2;+----+--------+----+--------+-------+| id | amount | id | weight | exist |+----+--------+----+--------+-------+|  2 |    200 |  2 |     22 |     0 |+----+--------+----+--------+-------+1 row in set (0.01 sec)

從上可知,第一條查詢使用 ON 條件決定了從 LEFT JOIN的 product_details表中檢索符合的所有資料行。第二條查詢做了簡單的LEFT JOIN,然後使用 WHERE 子句從 LEFT JOIN的資料中過濾掉不合格資料行。

(3).盡量避免子查詢,而用join

往往效能這玩意兒,更多時候體現在資料量比較大的時候,此時,我們應該避免複雜的子查詢。如下:

PASS

insert into t1(a1) select b1 from t2 where not exists(select 1 from t1 where t1.id = t2.r_id); 

Great

insert into t1(a1)  select b1 from t2  left join (select distinct t1.id from t1 ) t1 on t1.id = t2.r_id   where t1.id is null;  

這個可以參考mysql的exists與inner join 和 not exists與 left join 效能差別驚人

補充:MySQL STRAIGHT_JOIN 與 NATURAL JOIN的使用

感謝網友** 折翼的鳥** 給出的提醒。

長話短說:straight_join實現強制多表的載入順序,從左至右,如:

...A straight_join B on A.name = B.name 

straight_join完全等同於inner join 只不過,join文法是根據“哪個表的結果集小,就以哪個表為驅動表”來決定誰先載入的,而straight_join 會強制選擇其左邊的表先載入。

往往我們在分析mysql處理效能時,如(Explain),如果發現mysql在載入順序不合理的情況下,可以使用這個語句,但往往mysql能夠自動的分析並處理好。

更多內容參考:MySQL STRAIGHT_JOIN 與 NATURAL JOIN
和MySQL最佳化的奇技淫巧之STRAIGHT_JOIN

八.參考:

A Visual Explanation of SQL Joins

五種提高 SQL 效能的方法

關於 MySQL LEFT JOIN 你可能需要瞭解的三點

Mysql Join文法解析與效能分析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.