外連線轉換為內連線的情況

gaopengtttt發表於2016-08-05
一般的情況下外連線如下a right join b on a.id=b.id 那麼b一定要作為驅動表,原因在於只有b作為驅動表才能得到完整的結果集,如果a作為驅動,那麼返回的結果集
可能不完整,但是在特殊的情況的,可能將外連線轉換為內連線
考慮如下的情況


  id  name
  1   g1
  1   g2
  2   g3
  2   g4

a
  id name
  2  gname2

使用如下語句:
select b.id,a.id from 
a right join b on a.id=b.id 
where a.id=2;

先不考慮where a.id=1;
做外連線返回的值應該為
b.id a.id
1     null
1     null
2     2
2     2

現在來考慮a.id =2 ;
那麼如果這樣過濾那麼結果集合如下:

b.id a.id
2     2
2     2

這正是內連線的得到的結果集,也就是說只要a.id 限定為一定固定的非空的值,內連線出來的結構集就能
完全的滿足謂詞條件過濾後得到結果的全部中間結果集,那麼資料庫將會進行轉換。MYSQL ORACLE都是如此

mysql:
mysql> explain select b.id,a.id from  a right join b on a.id=b.id  where a.id =2;
+----+-------------+-------+------+---------------+------+---------+------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                              |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------------------------------------------+
|  1 | SIMPLE      | a     | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using where                                        |
|  1 | SIMPLE      | b     | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------------------------------------------+
2 rows in set (0.00 sec)
a作為了驅動表
oracle:

SQL> select b.id from a right join b on a.id=b.id  where a.id=2;

Execution Plan
----------------------------------------------------------
Plan hash value: 652036164
---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     1 |    26 |     5  (20)| 00:00:01 |
|*  1 |  HASH JOIN         |      |     1 |    26 |     5  (20)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| A    |     1 |    13 |     2   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| B    |     2 |    26 |     2   (0)| 00:00:01 |


可以看到本該出現的 HASH JOIN OUTER 沒有出現。

但是如果將條件where a.id=2;改為where a.id is null;那麼顯然這種轉換不合理,因為
內連線出來的結果集已經不能滿足 a.id is null;的要求。

為什麼要這樣轉換,我們知道在做連線的時候不管是NEST LOOP和HASN JOIN都應該把小表
作為驅動表,效率一般更高,那麼外連線限定死了順序可能大表做為驅動表,那麼效率
顯然更低,如果做了內連線的轉換那麼選擇的順序就更多,效率可能得到提高,當然
這和統計資料的精準度有很大的關係。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2123022/,如需轉載,請註明出處,否則將追究法律責任。

相關文章