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 user_action a on u.id = a.user_id

result:
    id  |   name    |   action
--------------------------------
    1   |   libk      |   jump    ①
    1   |   libk      |   kick     ②
    1   |   libk      |   jump    ③
    2   |   zyfon    |   run      ④
    3   |   daodao |   null      ⑤

分析:
注意到user_action中還有一個user_id=4, action=swim的紀錄,但是沒有在結果中出現,
而user表中的id=3, name=daodao的用戶在user_action中沒有相應的紀錄,但是卻出現在了結果集中
因爲現在是left join,所有的工作以left爲準.
結果1,2,3,4都是既在左表又在右表的紀錄,5是隻在左表,不在右表的紀錄

結論:
我們可以想象left join 是這樣工作的
從左表讀出一條,選出所有與on匹配的右表紀錄(n條)進行連接, 形成n條紀錄(包括重複的行,如:結果1和結果3),
如果右邊沒有與on條件匹配的表,那連接的字段都是null.
然後繼續讀下一條。

引申:
我們可以用右表沒有on匹配則顯示null的規律, 來找出所有在左表,不在右表的紀錄, 注意用來判斷的那列必須聲明爲not null的。
如:
sql:
    select id, name, action from user as u
    left join user_action a on u.id = a.user_id
    where a.user_id is NULL    
    (注意:1.列值爲null應該用is null 而不能用=NULL 
              2.這裏a.user_id 列必須聲明爲 NOT NULL 的)
result:
    id  |    name   |   action
    --------------------------
    3   |   daodao  |   NULL


Tips:

1. on a.c1 = b.c1 等同於 using(c1)
2. INNER JOIN 和 , (逗號) 在語義上是等同的
3.  當 MySQL 在從一個表中檢索信息時,你可以提示它選擇了哪一個索引。
    如果 EXPLAIN 顯示 MySQL 使用了可能的索引列表中錯誤的索引,這個特性將是很有用的。
    通過指定 USE INDEX (key_list),你可以告訴 MySQL 使用可能的索引中最合適的一個索引在表中查找記錄行。
    可選的二選一句法 IGNORE INDEX (key_list) 可被用於告訴 MySQL 不使用特定的索引。
4. 一些例子:
mysql> SELECT * FROM table1,table2 WHERE table1.id=table2.id;
mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;
mysql> SELECT * FROM table1 LEFT JOIN table2 USING (id);
mysql> SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id
    ->          LEFT JOIN table3 ON table2.id=table3.id;
mysql> SELECT * FROM table1 USE INDEX (key1,key2)
    ->          WHERE key1=1 AND key2=2 AND key3=3;
mysql> SELECT * FROM table1 IGNORE INDEX (key3)
    ->          WHERE key1=1 AND key2=2 AND key3=3;


以下爲mysql官方關於join的工作原理及注意事項的說明

    5.2.6 How MySQL Optimises LEFT JOIN and RIGHT JOIN


    A LEFT JOIN B in MySQL is implemented as follows:

    The table B is set to be dependent on table A and all tables that A is dependent on.
    The table A is set to be dependent on all tables (except B) that are used in the LEFT JOIN condition.
    All LEFT JOIN conditions are moved to the WHERE clause.
    All standard join optimisations are done, with the exception that a table is always read after all tables it is dependent on. If there is a circular dependence then MySQL will issue an error.
    All standard WHERE optimisations are done.
    If there is a row in A that matches the WHERE clause, but there wasn"
    If you use LEFT JOIN to find rows that don't exist in some table and you have the following test: column_name IS NULL in the WHERE part, where column_name is a column that is declared as NOT NULL, then MySQL will stop searching after more rows (for a particular key combination) after it has found one row that matches the LEFT JOIN condition.
    RIGHT JOIN is implemented analogously as LEFT JOIN.

    The table read order forced by LEFT JOIN and STRAIGHT JOIN will help the join optimiser (which calculates in which order tables should be joined) to do its work much more quickly, as there are fewer table permutations to check.

    Note that the above means that if you do a query of type:

    SELECT * FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key)
             WHERE b.key=d.key

    MySQL will do a full scan on b as the LEFT JOIN will force it to be read before d.

    The fix in this case is to change the query to:

    SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d (d.key=a.key)
             WHERE b.key=d.key

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章