本文導讀:
資料庫在通過連線兩張或多張表來返回記錄時,都會生成一張中間的臨時表,然後再將這張臨時表返回給使用者。例如在使用left jion時,on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄;where條件是在臨時表生成好後,再對臨時表進行過濾的條件。
on、where、having的區別
1、on、where、having這三個都可以加條件的子句中,on是最先執行,where次之,having最後。有時候如果這先後順序不影響中間結果的話,那最終結果是相同的。但因為on是先把不符合條件的記錄過濾後才進行統計,它就可以減少中間運算要處理的資料,按理說應該速度是最快的。
2、where應該比having快點的,因為它過濾資料後才進行sum,所以having是最慢的。但也不是說having沒用,因為有時在步驟3還沒出來都不知道那個記錄才符合要求時,就要用having了。
3、在兩個表聯接時才用on的,所以在一個表的時候,就剩下where跟having比較了。在這單表查詢統計的情況下,如果要過濾的條件沒有涉及到要計算欄位,那它們的結果是一樣的,只是where可以使用rushmore技術,而having就不能,在速度上後者要慢。
4、如果要涉及到計算的欄位,就表示在沒計算之前,這個欄位的值是不確定的,根據上篇寫的工作流程,where的作用時間是在計算之前就完成的,而having就是在計算後才起作用的,所以在這種情況下,兩者的結果會不同。
5、在多表聯接查詢時,on比where更早起作用。系統首先根據各個表之間的聯接條件,把多個表合成一個臨時表後,再由where進行過濾,然後再計算,計算完後再由having進行過濾。由此可見,要想過濾條件起到正確的作用,首先要明白這個條件應該在什么時候起作用,然後再決定放在那裡
例項說明
1、假設有兩張表:
表1:tab1
id size
1 10
2 20
3 30
表2:tab2
size name
10 AAA
20 BBB
20 CCC
兩條SQL:
1、select * form tab1 left join tab2 on (tab1.size = tab2.size) where tab2.name=’AAA’
2、select * form tab1 left join tab2 on (tab1.size = tab2.size and tab2.name=’AAA’)
第一條SQL的過程:
1、中間表on條件: tab1.size = tab2.size
tab1.id tab1.size tab2.size tab2.name
1 10 10 AAA
2 20 20 BBB
2 20 20 CCC
3 30 (null) (null)
2、再對中間表過濾where 條件:tab2.name=’AAA’
tab1.id tab1.size tab2.size tab2.name
1 10 10 AAA
第二條SQL的過程
中間表on條件: tab1.size = tab2.size and tab2.name=’AAA’(條件不為真也會返回左表中的記錄)
tab1.id tab1.size tab2.size tab2.name
1 10 10 AAA
2 20 (null) (null)
3 30 (null) (null)
2、例項2詳細說明
SQL語句如下:
SELECT *
FROM 表1
LEFT JOIN 表2 ON 表1.id = 表2.id AND 表2.Name != 'ff'
WHERE 表1.NAME != 'aa'
步驟1:返回笛卡爾積(SELECT * FROM 表1 CROSS JOIN 表2)
步驟2:應用ON篩選器(當前的條件為 表1.id = 表2.id AND 表2.Name != 'ff')
步驟3:新增外部行
這一步只對OUTER JOIN起作用,如果是LEFT JOIN會以左邊的表為保留表,如果是RIGHT JOIN會以右邊的表為保留表。所謂外部行是指,保留表中的行。即使第二步的ON過濾掉了一些行,在這一步,會根據保留表新增第二步過濾掉的行。當前的例子,不存在這種情況。
步驟4.應用WHERE篩選器(當前是Name != ‘aa’)過濾前三步所生成虛擬表的資料。
總結:
1、如果SQL用的是Left Join ,On後面的條件對Left的表沒有作用,只對Right的表有過濾作用,Where語句可以對Left的表有過濾作用
2、如果SQL用的是Right Join ,On後面的條件對Right的表沒有作用,只對Left的表有過濾作用,Where語句可以對Right的表有過濾作用