SQL 深入"了解" sqlserver 表連接 join 及性能調優化


  問題 :

     1.什么是內連接(inner)和外聯結(outer)

     2. SQL server 表連接 (FROM--AND 法, JOIN -- ON 法)的區別.

     3.表連接及多表連接的SQL語句執行順序,和性能調優.


1.第一個問題,首先要明白如何使用JOIN 和 ON 關鍵字作表連接。

    申明:下文中所用的等價,可能指的是邏輯上的等價(即產生相同的結果集),也可能是執行順序上的等價,甚至是所產生的執行計划或者執行效率等價。因為很多時候用戶只要寫普通的sql ,而sql server 會跟據自己的優化 配置和執行計划,產生執行步驟,這些步驟也許和你寫的sql很符合,也許更優,當然也可能不符合你的需求。這需要很多的積累,我也只是淺嘗輒止,所以沒有能力做過多論述。具體問題具體分析,這里只能提供大體思路。

  1)join 的5種方式 :

    inner join ; left join; right join; full join; cross join;

    其中inner  join可以省去inner 關鍵字。 left/right join 與left/right out join 等價。

    full join 與 同時 left join 和 right join 等價。

    cross join 為將兩張表笛卡爾集   

 


 

  2) JOIN -- ON 語句的執行順序:

    例句:

SELECT * FROM A LEFT JOIN B ON A.ID = B.ID AND A<>0 WHERE A.name = 'x'  

    注意在作on  連接后 的and 子句 和where 子句 。  他們有什么不同!。。。。。。

    邏輯上解釋:(不考慮執行計划中執行步驟和作嵌套連接等具體方式,這里只討論如何思考邏輯上的步驟) 

        執行順序是: FROM --> JOIN --> ON -->AND--> LEFT--> WHERE -->SELECT

        A步驟. 先將兩張表根據ON 條件 作連接(邏輯上,相等於將兩張表笛卡爾集后根據ID相等條件篩選數據,實際情況后面分析) 

        B步驟. 根據ON 后面,WHERE 之前 的 AND 條件篩選數據

        C步驟. 跟據LEFT 無論如何,要保證A表的數據完整性。所以在上一步驟產生的結果集中補齊A表因無法比與B表匹配而被AND 條件篩選的掉的數據;

        D步驟. 再根據WHERE篩選結果集。 

    示例:(為了能更好的這一過程,通過實例先思考)

        

CREATE TABLE EMPLOY  (NAME    VARCHAR(10),     DEPTNO    INTEGER );     

INSERT INTO EMPLOY (NAME, DEPTNO) VALUES  
 ('張三',10),  
 ('李四',20),  
 ('王五',10),  
 ('趙紅',20);    

 
CREATE TABLE DEPARTMENT  (DEPTNO    INTEGER,      DEPTNAME    VARCHAR(10) ); 

INSERT INTO DEPARTMENT (DEPTNO, DEPTNAME) VALUES 
(10, '市場部'),
(20, '技術部');


--查詢一下所有的員工的姓名和部門名為市場部的部門 

    

也許你的SQL 會寫成這樣:

SELECT E.NAME,D.DEPTNAME 
FROM EMPLOY  E LEFT JOIN DEPARTMENT D ON E.DEPTNO=D.DEPTNO   
WHERE D.DEPTNAME='市場部' 

仔細讀題目,是要查詢“所有”員工的姓名,所以肯定要保證員工表的數據完整性。如果使用where,當然不能保證員工表的完整拉。

還記得 在 ON 關鍵字后 ,WHERE 關鍵字前的條件篩選方式么???

SELECT E.NAME,D.DEPTNAME FROM EMPLOY  E LEFT JOIN DEPARTMENT D ON E.DEPTNO=D.DEPTNO AND D.DEPTNAME='市場部'  

這樣就對了!!

產生的結果很奇怪

張三 市場部
李四 NULL
王五 市場部
趙紅 NULL

為什么結果是這樣呢? 深入理解下前面所說的SQL 語句執行順序 

    舉個例子:分別執行看看結果,結合上個例子想想(以下ABC步驟意思是前面說的ABCD四個步驟)

--執行A步驟等價的邏輯SQL
SELECT * FROM EMPLOY  E   JOIN DEPARTMENT D   ON E.DEPTNO=D.DEPTNO
--執行B步驟等價的邏輯SQL
SELECT * FROM EMPLOY  E   JOIN DEPARTMENT D   ON E.DEPTNO=D.DEPTNO and  D.DEPTNO=40
--執行C步驟等價的邏輯SQL
SELECT * FROM EMPLOY  E  left JOIN DEPARTMENT D   ON E.DEPTNO=D.DEPTNO and  D.DEPTNO=40

  3)表連接在執行計划,或者是真正的執行方式:

  首先要理解下執行計划,看看SQL語句如何在 SQL SERVER   內部中真正實現這些復雜操作;其中SQL SERVER JOIN 的三種方式(Nested Loops join,Merge Join,Hash Join)要有所了解。如果不懂,可以去http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html 看看學習。

  我的私人理解:

    A. Nested Loops join :外表縣進行逐條掃描,而內表,根據ON的連接條件,快速SEEK內表看是否有符合的數據(SEEK不是SCAN)。這樣產生兩張表JOIN后集合。

     B. Merge Join : 用於兩張表差不多大,而且在連接字段上有索引。

    C.  Hash Join : 兩張表都是數據量很大。

  雖然不是太明白具體如何判斷,但是SQL SERVER 會自動判斷使用哪種方式,所以不需要太關心,除非是做DBA的。重點了解下Nested Loops join。

 


  4)FROM , JOIN , ON , AND , WHERE  總結  

  鋪墊了這么多,終於回到關鍵問題: 平時看到很多SQL 寫法 有的用WHERE  and 進行表連接,有的用JOIN ON 作表連接。這里面不能隨便,寫不好即影響結果,又阻礙執行效率。可以查看更多詳細資料:http://blog.csdn.net/shangboerds/article/details/5213264

    

SELECT E.NAME,D.DEPTNAME FROM EMPLOY  E LEFT JOIN DEPARTMENT D ON E.DEPTNO=D.DEPTNO   
WHERE D.DEPTNAME='市場部' 

SELECT E.NAME,D.DEPTNAME FROM EMPLOY  E LEFT JOIN DEPARTMENT D ON E.DEPTNO=D.DEPTNO 
AND D.DEPTNAME='市場部'  
-- 不論邏輯上還是結果上都不等價

 

  現實SQL查詢中,一般都不止兩個表連接,一般是多表連接查詢! 幾個常見錯誤:

  1。胡亂使用LEFT join :由於分析過執行步驟, LEFT 關鍵字是要在“兩張”表連接完成后(思考下多表連接),再對表相當於進行掃描部全的過程,所以會耗費很多時間。

  2。分不清表連接 (FROM--AND 法, JOIN -- ON 法)的區別;如下兩個SQL:

SELECT *
FROM A 
INNER JOIN B ON A.ID = B.ID AND B<>0
INNER JOIN C ON A.ID = B.ID AND C<>0


SELECT *
FROM A 
INNER JOIN B ON A.ID = B.ID 
INNER JOIN C ON A.ID = B.ID 
WHERE 
    B<>0
AND C<>0
--此寫法效率比上面兩種都差,尤其表越多,效果越明顯

 

   思考表連接的的SQL執行順序。。。前者兩張表JOIN 后 馬上篩選部分結果在與另一張表JOIN 。后者先將三張表JOIN后再篩選。所以很明顯前者效率比后者高.

  3。再添加一條SQL :

  

SELECT * 
FROM A , B , C
WHERE A.ID = B.ID 
AND A.ID = C.ID
AND B<>0 
AND C<>0

  此結果和第一條SQL一樣效率不錯! 從邏輯上看,似乎SQL 會先將表JOIN 后再篩選,但實戰結果。是先篩選再JOIN !因為SQL SERVER 會內部分析,產生一個最優的執行計划,所以不用你操心,自動幫你處理了!而使用JOIN ON 的話,就好像是使用強制命令,告訴數據庫,就是要按你的方式處理結果,數據庫只好服從!! 所以思考SQL寫法不能只說要效率,同時還要注重結果對了,這才是關鍵!

  4。本人一次看別人SQL,就是不明白作表連接查詢,為什么WHERE后面要進行大量的WHERE條件篩選,而且都是無關業務邏輯的。在我的傳統觀念看來,執行WHERE 語句是需要對全表進行掃描的,這樣因該會增加查詢時間。現在結合前面所講的,因為不論是(FROM--AND 還是 JOIN--ON)方式,再與第三張表JOIN之前都應該盡量先篩選一部分結果(可能是大部分結果)。這樣速度會大大提升!

 

  

 

  表連接人人都會,可真要說的清清楚楚,也許還需要花點功夫和時間去測試和總結吧。說起來因該有很大的文章,本人知識積累還不夠,還希望有人能提點提點,斧正補充一下!!  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM