程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> 數據庫性能優化JOIN方法說明(2)

數據庫性能優化JOIN方法說明(2)

編輯:關於SqlServer


     提示:看到很多朋友對數據庫的理解、認識還是沒有突破一個瓶頸,而這個瓶頸往往只是一層窗紙,越過了你將看到一個新世界。


JOIN方法說明

數據庫中,象tableA inner join tableB、tableA left out join tableB這樣的SQL語句是如何執行join操作的?就是說SQL Server使用什麼算法實現兩個表數據的join操作?

sql Server 2000有三種方式:nested loop、merge、hash。Oracle也是使用這三種方式,不過Oracle選擇使用nested loop的條件跟SQL Server有點差別,內存管理機制跟SQL Server不一樣,因此查看執行計劃,Oracle中nested loop運用非常多,而merge和hash方式相對較少,SQL Server中,merge跟hash方式則是非常普遍。

以SQL Server 2000為例對這三種方式進行說明,穿插在裡面講解執行計劃的一些初級使用。

1. nested loop join

1.1 示例SQL

select ... from tableA inner join tableB on tableA.col1=tableB.col1 where tableA.col2=? and tableB.col2=?tableA中沒有建立任何索引,tableB中在col1上有建立一個主鍵(聚集索引)。

1.2 算法偽代碼描述

    foreach rowA in tableA where tableA.col2=?{search rowsB from tableB where tableB.col1=rowA.col1 and tableB.col2=? ;if(rowsB.Count<=0)discard rowA ;elSEOutput rowA and rowsB ;}

join操作有兩個輸入,上面例子中tableA是outer input,用於外層循環;tableB是inner input,用於循環內部。下面針對執行計劃描述一下SQL Server完成這個操作的具體步驟。

1.3 查看執行計劃方法

移到文章最前面。

1.4 執行步驟

下面是示例SQL的執行計劃圖。nested loop操作的右邊,位於上面的是outer input,位於下面的是inner input。你不能夠根據join中哪個表出現在前面來確定outer input和inner input關系,而必須從執行計劃中來確定,因為SQL Server會自動選擇哪個作為inner input。

a) 對tableA執行Table Scan操作。這個操作的輸入是tableA表中的數據,這些數據位於磁盤上,操作過程中被加載到內存;輸出是符合條件的記錄集,將作為b)的outer input。在這個操作中,tableA.col1=?的條件會被使用。

b) 執行上面偽代碼描述的nested loop操作。對a)中的每個輸出記錄,執行步驟c)。

c) 對tableB執行Clustered Index Seek操作。這個操作是在nested loop循環裡面執行的,輸入是tableB表的聚集索引數據。它使用tableB.col1=rowA.col1和tableB.col2=?這兩個條件,從tableB的聚集索引中選擇符合條件的結果。

d) 構造返回結果集。從nested loop的輸出中,整理出select中指定的字段,構造最終輸出結果集。

1.5 進階說明

上面例子對inner input使用的是聚集索引,下面看一下非聚集索引的情況,加強對執行計劃的理解、分析能力。

把tableB col1上的主鍵修改為非聚集方式,示例的SQL語句執行計劃.

前面三個執行步驟a)、b)、c)跟1.4中一樣,有一點需要注意的是,步驟c)是執行Index Seek操作,它跟Clustered Index Seek有區別。聚集索引的根節點是每一條實際數據記錄,而非聚集索引的根節點是對聚集索引根結點鍵值的引用(如果表存在聚集索引),或者是對實際數據記錄rowid的引用(指沒有聚集索引的表,這種表稱為heap表)。Clustered Index Seek執行之後,實際的物理數據記錄已經被加載到內存中,而Index Seek操作之後,並沒有加載實際的物理數據記錄,而只是非聚集索引的根結點數據,其中只包含了索引字段數據以及引用的聚集索引鍵值或者rowid。SQL Server在這個步驟中使用非聚集索引根結點數據中的索引字段值,與outer input中的記錄(rowA)關聯字段進行匹配,判斷是否是符合條件的結果,如果是,則將非聚集索引根結點數據結構保存到nested loop操作的輸出數據結構中,並且會創建一個書簽(Bookmark),指示在必要的時候需要根據這個書簽去獲取引用的數據。

d) 執行Bookmark Lookup操作。nested loop操作的輸出是一個內存數據結構,在從這個內存數據結構中整理出整個查詢語句的輸出結果集之前,需要處理前面的書簽引用問題,Bookmark Lookup操作就是根據書簽中引用的聚集索引鍵值或者rowid獲取具體記錄數據。

e) Filter過濾操作。回顧前面幾個操作,在執行nested loop時只是使用非聚集索引的索引字段(tableB.col1)跟outer input的關聯字段進行匹配,到目前為止還沒有使用tableB.col2=?這個條件,這個操作就是使用tableB.col2=?對Bookmark Lookup的輸出進行過濾。

看的仔細的人到這裡後可能會有幾個疑問,1. tableA.col2=?怎麼沒有一個Filter操作?2. 在1.4中為什麼沒有出現Filter操作?解釋如下:1. 在tableA上面執行的是Table Scan操作,是直接對每條實際數據進行掃描,在這個掃描過程中可以使用tableA.col2=?這個條件進行過濾,避免一個額外的Filter操作。鼠標移動到Table Scan操作上,從提示信息的參數(Argument)裡面可以看到tableA.col2=?的條件已經被運用上了。2. 前面說過,聚集索引的根節點是實際數據記錄,執行Clustered Index Seek的時候,最終也是掃描到了實際數據記錄,在這個過程中運用tableB.col2=?這個條件,同樣避免一個額外的Filter操作。這就是1.4中沒有Filter操作的原因。

f) 構造返回結果集。跟1.4步驟d)一樣。

1.6 nested loop使用條件

任何一個join操作,如果滿足nested loop使用條件,查詢優化過程中SQL Server就會對nested loop的成本(I/O成本、CPU成本等)進行評估,基於評估結果確定是否使用這種join方式。

使用nested loop方式的條件是:a) outer input的記錄數不大,最好是在1000-2000以下,一般超過3000就很難說了,基本不大會選擇nested loop。b) 作為inner input的表中,有可用於這個查詢的索引。

這是因為outer input記錄數不大,意味著外層循環次數比較小;inner input上有可用的索引,意味著在循環裡面搜索inner input表中是否存在匹配的記錄時,效率會很高,哪怕inner input表實際記錄數有幾百萬。基於這兩個條件,nested loop的執行效率非常高,在三種join方式裡面,是內存和CPU消耗最少的一種(不合理的強制指定nested loop方式除外)。

關於使用條件另外的說明:outer input的記錄數,並不是指outer input表中實際記錄數,例如示例SQL中,如果tableA在col2上有維護統計信息(存在col2的索引或者是單獨維護的統計信息),並且tableA.col2=?的條件值符合SARG(可搜索參數)形式,那麼查詢編譯時刻SQL Server就能夠利用統計信息和條件值評估出符合條件的記錄數,查詢執行時刻符合條件tableA.col2=?的記錄才被用於外層循環。inner input表中有可用的索引,是指inner input表中用於和outer input表關聯的字段(一個或多個字段)能夠命中某個索引(這些字段的部分或者全部出現在某個索引字段的前面)。

符合上面的條件,也不是說SQL Server 100%就會選擇nested loop。因為SQL Server的查詢優化器是基於成本評估的,如果其它方案評估出的成本勝過這個,SQL Server會選擇其它的join方式。舉個例子,如果inner input上符合條件的索引是非聚集索引,這樣SQL Server可能需要一個額外的Bookmark Lookup操作獲取實際記錄數據,如果inner input表數據量非常大,索引碎片程度很高等情況,可能導致Bookmark Lookup成本非常高,SQL Server會嘗試其它join方案的評估選擇。

1.7 強制指定nested loop方式

使用loop關鍵字實現,例如tableA inner loop join tableB,將強制SQL Server使用nested loop方式執行這個join操作。或者使用option選項,例如tableA inner join tableB option(loop join) nested loop算法有它適用的范圍,在這個范圍之內效率是最高的,超出這個范圍效率反而很差,除非你有十分的把握,不要隨意強制指定join方式。

接下來就不再象上面這樣詳細的講述了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved