Parallel Query Bitmap
生活随笔
收集整理的這篇文章主要介紹了
Parallel Query Bitmap
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Degree of Parallelism(并行度) ??? 一個查詢使用并行來處理時,SQL Server為該查詢分配多個線程,每個線程使用一個CPU進行操作。Degree of Parallelism就是SQL Server為并行查詢分配的線程數量,也表明這個并行查詢將使用多少個CPU進行并行處理。 ??? Exchange Oprators(交換操作) ??? 查詢語句的執行計劃中,通常是并行操作和串行操作結合在一起。并行操作要求將輸入數據流(data stream)切分成多個(即degree of parallelism)部分,分別分配給各個線程進行并行處理。并行查詢包括幾個數據流的交換操作(exchange operator),用以管理并行計劃的執行。 ??? Distribute Steams ??? 執行計劃中顯示為Parallelism/Distribute Steams。通常情況下,如果在一個串行操作之后緊接著一個并行操作,則這個并行操作將從前一個串行操作接收一個input stream。Distribute Steams就是并行查詢中將單個input stream分發到多個output stream中的操作。 ??? 例如一個serial table scan產生一個4000記錄的output stream,假設在這個table scan之后是一個并行操作,則在這兩個操作之間必須需要一個Distribute Steams操作,向并行操作的各個線程分發input stream。如果degree of parallelism為4,SQL Server根據關鍵字段,將這個4000記錄的stream分發成4個大致相當的stream,分別作為4個線程的input。< /font> ??? Distribute Streams操作之后,每一條input stream中的記錄,將出現在某一個output stream中,記錄的內容和格式不會發生任何變化。SQL Server自動在output stream中保留input stream中各記錄的相對順序。 ??? 通常,將使用Hashing以確定每一條輸入記錄被分發到哪一個output stream中。 ??? Gather Streams ??? 執行計劃中顯示為Parallelism/Gather Streams。在并行操作結束之后,輸出結果保留在多個stream中。Gather Streams將并行操作的多個output stream收集到單個stream中。 ??? Gather Streams對多個stream進行合并過程中,記錄的內容和格式不會發生任何變化。如果各個input stream都是排序的,則Gather Streams的output stream也是排序的。 ??? Redistribute Streams/Repartition Streams ??? 執行計劃中顯示為Parallelism/Repartition Streams。在一系列的并行操作中,在某個并行操作之后,可能需要對各個stream進行重新組合,才能夠進入下一個并行操作。< /font> ??? 例如Merge Join、Hash Join,都需要兩個input。這些操作的并行計劃中,每個并行的線程都應當擁有兩個獨立的input,各自執行Merge Join、Hash Join操作,在并行Merge/Hash Join之后,使用Gather Streams操作,就得到完整的Merge/Hash Join的結果。如果在Merge/Hash Join前是一系列的并行計劃,則在進入Merge/Hash Join時,各個并行線程擁有的stream可能不滿足"獨立的input"這個條件,此時就需要對進入Merge/Hash Join的各個stream進行重組,以使并行的各個線程獨立的完成Merge/Hash Join中的一部分。 ??? 每一條input stream中的記錄,在Repartition Streams操作之后將出現在其中一個output stream中,記錄的內容和格式不會發生任何變化。如果各個input stream都是排序的,則Repartition Streams的各個output stream也是排序的。 ? ??? 示例< /div> ??? 示例中要使用到2個table: ??? TblBuyerItem( ??????? UserID NVARCHAR(40) NOT NULL, ??????? OrgID NVARCHAR(40) NOT NULL, ??????? ItemID NVARCHAR(40) NOT NULL) ??? 這個表的Clustered Index:OrgID,ItemID,記錄數為150萬。 ??? #alert_asn_shipoverdue( ??????? ORG NVARCHAR(40) NOT NULL, ??????? ITEM NVARCHAR(40) NOT NULL, ??????? VENDOR NVARCHAR(40) NOT NULL) ????這是個臨時表,沒有PK,沒有任何index,記錄數150。 執行的SQL如下(沒有使用到TblBuyerItem的Clustered Index): ??? SELECT a.UserID
??? FROM TblBuyerItem a
??? INNER JOIN #alert_asn_shipoverdue b?ON b.ORG=a.OrgID AND b.ITEM=a.ItemID
??? OPTION(MERGE JOIN) ??? 執行計劃如下圖(裁減掉了個別步驟,點擊可以放大查看):
??? 執行計劃中,圖標右下腳有個黃色小圓圈,里面有三個并行小箭頭,則表明這個操作是并行執行的。 ??? 并行處理中的stream數據流如下圖所示: ???
? ??? 上圖示例degree of parallelism為3時的執行情況。執行過程介紹如下: ??? 先在#alert_asn_shipoverdue上執行table scan,然后根據key column ORG、ITEM的值,為并行的Merge Join操作將#alert_asn_shipoverdue的數據分發到三個stream中,假設編號分別為B1、B2、B3。三個線程各自對所獲得的stream創建bitmap,然后進行排序。 ??? 接下來,三個線程并行的在TblBuyerItem上執行Clustered Index Scan。操作完成后每個線程獲得一個output stream,假設編號分別為A1'、A2'、A3'。現在A1'、A2'、A3'還不能與B1 、B2、B3匹配成A1'-B1、A2'-B2、A3'-B3,獨立的進行Merge Join操作,因此根據key column OrgID、ItemID的 值,對A1'、A2'、A3'執行Repartition Streams操作,為接下來的Merge Join重組A1'、A2'、A3',并且使用bitmap過濾記錄。假設重組后的stream分別編號為A1、A2、A3,此時,三個線程分別使用A1 -B1、A2-B2、A3-B3作為輸入,執行Merge Join操作。在Merge Join操作前,兩個input都必須是經過排序的,因此每一個stream在進入Merge Join操作前都有一個Sort操作。 ??? 最后,Gather Streams操作從三個線程的output stream中收集合并記錄集,得到完整的Merge Join結果記錄集。 ? ??? Parallel query并不能節約內存、CPU的資源開銷,因為將stream進行Distribute、Repartition、Gather都需要消耗更多的資源。但是Parallel query也許可以節約query的執行時間。 ??? ??? Bitmap(位圖) ??? 在上面的示例中,可以看到Bitmap/Bitmap Create的操作。 ??? 在MANY-TO-MANY的Join中,兩個表可能存在大量不匹配的記錄。在上面的示例中,#alert_asn_shipoverdue的記錄只有150,而TblBuyerItem的記錄是1,500,000,如果直接對兩個表進行 Merge Join,就必須為TblBuyerItem的1,500,000記錄進行排序,這是一個成本非常高的操作。而在1,500,000記錄中,只有少量記錄符合匹配條件。Bitmap操作在Join操作前,快速的對數據進行一次初步的過濾,減少Join操作的開銷。 ??? Bitmap in Merge Join ??? 仍以上面的示例來說明,在Parallelism/Distribute Streams操作之后,每個線程得到一個input stream,接下來各個線程為自己的stream創建bitmap。我們假設分配給線程1的stream編號為B1。Bitmap創建完成后,包含一系 列0、1的值,為1的位代表對應于這一位,該stream中存在相應的記錄;為0的位代表對應于這一位,該stream中不存在相應的記錄。在 Parallelism/Repartition Streams操作時,從input stream中循環取出每條記錄,先確定該記錄應當進入哪一個output stream中。我們假設某一條記錄被確定應當放入編號為A1的output stream,這個output stream A1將與stream B1匹配,被分配給線程1,作為線程1 Merge Join的兩個輸入。接下來SQL Server使用這條記錄,查詢與output stream A1對應的stream B1的bitmap。如果相應的位值為0,則說明這條記錄在B1中不可能存在匹配的記錄,因此這條記錄被忽略掉,不會放入output stream A1中;如果相應的位值為1,則說明這條記錄在B1中可能存在匹配的記錄,該記錄被放入output stream A1,繼續在后續的Merge Join中進行精確的匹配。 ??? 關于bitmap具體如何創建還不清楚,猜想大致應當是如下的一個過程:使用hash算法進行操作,在查詢優化期間基于#alert_asn_shipoverdue 的Join字段ORG、ITEM可能出現的唯一值數量而確定bitmap的大小。這個過程和Hash Join中確定hash table buckes數量(和大小)有點類似。執行期間,先使用這個bitmap大小的值創建bitmap,初始化各個位均為0。然后為#alert_asn_shipoverdue循環,對每一個ORG、ITEM的組合值進行hash,得到的hash value對應于bitmap中的某一個位,將這個位設為1。 ??? 基于上面bitmap的創建過程,在Parallelism/Repartition Streams操作時,某一條記錄被確定進入哪一個output stream之后,即可以找到相對應stream的bitmap。對這條記錄OrgID、ItemID的值,使用在bitmap創建時相同的hash算法,用得到的hash value查找對應的位。 ? ??? 下面看一下示例中bitmap的使用帶來的效果(點擊可以放大查看): ?
??? 在對TblBuyerItem進 行scan時,Row Count為1,543,050。在Repartition Streams操作中,WHERE:(PROBE([Bitmap1002])=TRUE)表明對bitmap的使用,Row Count 3,138。另外,從上圖中可以看出,示例的SQL實際執行時使用了8 CPU。 ??? 附加說明:在上面的示例中,#alert_asn_shipoverdue很小,并且bitmap的create 和probe過程,其實已經和Hash Join差不多。事實上,讓SQL Server自動選擇Join Type時,使用的是Hash Join(參考[Join Type實例說明],使用的是同樣的示例)。使用Hash Join時用的是serial方式,耗時4秒多;上面的示例耗時2秒;上面示例不使用并行處理(MAXDOP 1)時,耗時1分30多秒。 ? ??? Merge Join中,在outer input的分支進入Merge Join前,必須有一個Sort操作,SQL Server才能使用bitmap。這是因為這個Sort操作使得整個outer input的分支處理完畢之后,才開始inner input分支的執行,最后再進入Merge Join操作。這樣inner input分支執行時,才能使用在outer input分支上創建的bitmap。如果沒有這個Sort操作,SQL Server會同時開始處理outer input分支和inner input分支,這樣是無法使用bitmap的。 ??? 我們可以在上面的示例上做一個驗證。假如在#alert_asn_shipoverdue有一個clustered index(ORG,ITEM),那示例中的SQL語句執行時會是什么狀況?在(ORG,ITEM)上創建clustered index后,執行計劃變成下圖所示(點擊可以放大查看):
??? 對#alert_asn_shipoverdue的Table Scan變成了Clustered Index Scan,得到的stream是按照ORG、ITEM排序的。 ??????
??? 現在,在Parallelism/Distribute Streams操作前的stream是按ORG、ITEM排序的,因此Distribute Streams的各個output stream也是按照ORG、ITEM排序的,因此這個outer input分支在Merge Join前不再需要Sort操作,這樣的話就無法使用bitmap了。 ??? 從執行計劃圖中可以看到,inner input的分支,在TblBuyerItem的Table Scan之后,箭頭的大小一直到Merge Join操作沒有變化,說明在這個分支上一系列的操作中,記錄數基本上沒有什么變化。下圖是TblBuyerItem的Table Scan和Parallelism/Repartition Streams的詳細信息(點擊可以放大查看): ?
??? 在這個驗證中,沒有使用bitmap的平均執行時間是1分10秒。 ? ??? Bitmap in Hash Join ??? Hash Join中的bitmap,總體上來講跟Merge Join中的處理是一樣的。在build input(outer input)上構造hash table時是并行處理的,構造hash table的同時也為每個build input的stream創建bitmap。當整個build階段完成后,再開始probe階段,因此在probe階段執行時已經可以使用bitmap, 接下來的操作就跟Merge Join中Probe Bitmap操作完全一樣。 ? ??? SQL Server只在Parallel Query中使用bitmap,估計是Probe Bitmap結合Parallel Query中的Repartition操作,可節約的成本比較明顯。在Serial Query中,額外的去Probe Bitmap,可能對查詢的執行并不能帶來明顯的改善。 ? ??? OK,It's over now. 下面回顧一下示例的語句在各種情況下的執行效果: ???????
? ??? 參考: ??? MSDN - Parallel Query Processing ??? MSDN - Bitmaps in Microsoft SQL Server 2000 ??? MSDN - Logical and Physical Operators
??? FROM TblBuyerItem a
??? INNER JOIN #alert_asn_shipoverdue b?ON b.ORG=a.OrgID AND b.ITEM=a.ItemID
??? OPTION(MERGE JOIN) ??? 執行計劃如下圖(裁減掉了個別步驟,點擊可以放大查看):
??? 執行計劃中,圖標右下腳有個黃色小圓圈,里面有三個并行小箭頭,則表明這個操作是并行執行的。 ??? 并行處理中的stream數據流如下圖所示: ???
? ??? 上圖示例degree of parallelism為3時的執行情況。執行過程介紹如下: ??? 先在#alert_asn_shipoverdue上執行table scan,然后根據key column ORG、ITEM的值,為并行的Merge Join操作將#alert_asn_shipoverdue的數據分發到三個stream中,假設編號分別為B1、B2、B3。三個線程各自對所獲得的stream創建bitmap,然后進行排序。 ??? 接下來,三個線程并行的在TblBuyerItem上執行Clustered Index Scan。操作完成后每個線程獲得一個output stream,假設編號分別為A1'、A2'、A3'。現在A1'、A2'、A3'還不能與B1 、B2、B3匹配成A1'-B1、A2'-B2、A3'-B3,獨立的進行Merge Join操作,因此根據key column OrgID、ItemID的 值,對A1'、A2'、A3'執行Repartition Streams操作,為接下來的Merge Join重組A1'、A2'、A3',并且使用bitmap過濾記錄。假設重組后的stream分別編號為A1、A2、A3,此時,三個線程分別使用A1 -B1、A2-B2、A3-B3作為輸入,執行Merge Join操作。在Merge Join操作前,兩個input都必須是經過排序的,因此每一個stream在進入Merge Join操作前都有一個Sort操作。 ??? 最后,Gather Streams操作從三個線程的output stream中收集合并記錄集,得到完整的Merge Join結果記錄集。 ? ??? Parallel query并不能節約內存、CPU的資源開銷,因為將stream進行Distribute、Repartition、Gather都需要消耗更多的資源。但是Parallel query也許可以節約query的執行時間。 ??? ??? Bitmap(位圖) ??? 在上面的示例中,可以看到Bitmap/Bitmap Create的操作。 ??? 在MANY-TO-MANY的Join中,兩個表可能存在大量不匹配的記錄。在上面的示例中,#alert_asn_shipoverdue的記錄只有150,而TblBuyerItem的記錄是1,500,000,如果直接對兩個表進行 Merge Join,就必須為TblBuyerItem的1,500,000記錄進行排序,這是一個成本非常高的操作。而在1,500,000記錄中,只有少量記錄符合匹配條件。Bitmap操作在Join操作前,快速的對數據進行一次初步的過濾,減少Join操作的開銷。 ??? Bitmap in Merge Join ??? 仍以上面的示例來說明,在Parallelism/Distribute Streams操作之后,每個線程得到一個input stream,接下來各個線程為自己的stream創建bitmap。我們假設分配給線程1的stream編號為B1。Bitmap創建完成后,包含一系 列0、1的值,為1的位代表對應于這一位,該stream中存在相應的記錄;為0的位代表對應于這一位,該stream中不存在相應的記錄。在 Parallelism/Repartition Streams操作時,從input stream中循環取出每條記錄,先確定該記錄應當進入哪一個output stream中。我們假設某一條記錄被確定應當放入編號為A1的output stream,這個output stream A1將與stream B1匹配,被分配給線程1,作為線程1 Merge Join的兩個輸入。接下來SQL Server使用這條記錄,查詢與output stream A1對應的stream B1的bitmap。如果相應的位值為0,則說明這條記錄在B1中不可能存在匹配的記錄,因此這條記錄被忽略掉,不會放入output stream A1中;如果相應的位值為1,則說明這條記錄在B1中可能存在匹配的記錄,該記錄被放入output stream A1,繼續在后續的Merge Join中進行精確的匹配。 ??? 關于bitmap具體如何創建還不清楚,猜想大致應當是如下的一個過程:使用hash算法進行操作,在查詢優化期間基于#alert_asn_shipoverdue 的Join字段ORG、ITEM可能出現的唯一值數量而確定bitmap的大小。這個過程和Hash Join中確定hash table buckes數量(和大小)有點類似。執行期間,先使用這個bitmap大小的值創建bitmap,初始化各個位均為0。然后為#alert_asn_shipoverdue循環,對每一個ORG、ITEM的組合值進行hash,得到的hash value對應于bitmap中的某一個位,將這個位設為1。 ??? 基于上面bitmap的創建過程,在Parallelism/Repartition Streams操作時,某一條記錄被確定進入哪一個output stream之后,即可以找到相對應stream的bitmap。對這條記錄OrgID、ItemID的值,使用在bitmap創建時相同的hash算法,用得到的hash value查找對應的位。 ? ??? 下面看一下示例中bitmap的使用帶來的效果(點擊可以放大查看): ?
??? 在對TblBuyerItem進 行scan時,Row Count為1,543,050。在Repartition Streams操作中,WHERE:(PROBE([Bitmap1002])=TRUE)表明對bitmap的使用,Row Count 3,138。另外,從上圖中可以看出,示例的SQL實際執行時使用了8 CPU。 ??? 附加說明:在上面的示例中,#alert_asn_shipoverdue很小,并且bitmap的create 和probe過程,其實已經和Hash Join差不多。事實上,讓SQL Server自動選擇Join Type時,使用的是Hash Join(參考[Join Type實例說明],使用的是同樣的示例)。使用Hash Join時用的是serial方式,耗時4秒多;上面的示例耗時2秒;上面示例不使用并行處理(MAXDOP 1)時,耗時1分30多秒。 ? ??? Merge Join中,在outer input的分支進入Merge Join前,必須有一個Sort操作,SQL Server才能使用bitmap。這是因為這個Sort操作使得整個outer input的分支處理完畢之后,才開始inner input分支的執行,最后再進入Merge Join操作。這樣inner input分支執行時,才能使用在outer input分支上創建的bitmap。如果沒有這個Sort操作,SQL Server會同時開始處理outer input分支和inner input分支,這樣是無法使用bitmap的。 ??? 我們可以在上面的示例上做一個驗證。假如在#alert_asn_shipoverdue有一個clustered index(ORG,ITEM),那示例中的SQL語句執行時會是什么狀況?在(ORG,ITEM)上創建clustered index后,執行計劃變成下圖所示(點擊可以放大查看):
??? 對#alert_asn_shipoverdue的Table Scan變成了Clustered Index Scan,得到的stream是按照ORG、ITEM排序的。 ??????
??? 現在,在Parallelism/Distribute Streams操作前的stream是按ORG、ITEM排序的,因此Distribute Streams的各個output stream也是按照ORG、ITEM排序的,因此這個outer input分支在Merge Join前不再需要Sort操作,這樣的話就無法使用bitmap了。 ??? 從執行計劃圖中可以看到,inner input的分支,在TblBuyerItem的Table Scan之后,箭頭的大小一直到Merge Join操作沒有變化,說明在這個分支上一系列的操作中,記錄數基本上沒有什么變化。下圖是TblBuyerItem的Table Scan和Parallelism/Repartition Streams的詳細信息(點擊可以放大查看): ?
??? 在這個驗證中,沒有使用bitmap的平均執行時間是1分10秒。 ? ??? Bitmap in Hash Join ??? Hash Join中的bitmap,總體上來講跟Merge Join中的處理是一樣的。在build input(outer input)上構造hash table時是并行處理的,構造hash table的同時也為每個build input的stream創建bitmap。當整個build階段完成后,再開始probe階段,因此在probe階段執行時已經可以使用bitmap, 接下來的操作就跟Merge Join中Probe Bitmap操作完全一樣。 ? ??? SQL Server只在Parallel Query中使用bitmap,估計是Probe Bitmap結合Parallel Query中的Repartition操作,可節約的成本比較明顯。在Serial Query中,額外的去Probe Bitmap,可能對查詢的執行并不能帶來明顯的改善。 ? ??? OK,It's over now. 下面回顧一下示例的語句在各種情況下的執行效果: ???????
? ??? 參考: ??? MSDN - Parallel Query Processing ??? MSDN - Bitmaps in Microsoft SQL Server 2000 ??? MSDN - Logical and Physical Operators
轉載于:https://www.cnblogs.com/wayne-ivan/archive/2007/06/27/797062.html
總結
以上是生活随笔為你收集整理的Parallel Query Bitmap的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高质量c/c++编程(5)
- 下一篇: 关于URL重写的一点心得