深入解析SQL Server並行執行原理及實踐(上)

分類:IT技術 時間:2016-10-13

在成熟領先的企業級數據庫系統中,並行查詢可以說是一大利器,在某些場景下他可以顯著的提升查詢的相應時間,提升用戶體驗.如SQL Server, Oracle等, mysql目前還未實現,而PostgreSQL在2015實現了並行掃描,相信他們也在朝著更健壯的企業級數據庫邁進.RDBMS中並行執行的實現方式大抵相同,本文將通過SQL Server為大家詳細解析SQL Server並行執行的原理及一些實踐.

準備知識

硬件環境-在深入並行原理前,我們需要一些準備知識,用以後面理解並行.首先是當下的硬件環境,社會信息化建設,互聯網的普及,硬件工藝的大發展…我們現在的硬件設備的性能雖然已經不復摩爾定律的神奇,但已經相當豐富了,存儲上15K RPM的硬盤,SSD,PCI-E SSD使得磁盤作為數據庫系統的”終極”瓶頸得到了一定的緩解,而內存上百G內存也早已不是小機的”特性”了,PC Server上已經很普遍.

在處理能力上,由於現今物理工藝上的極限,單顆CPU處理能力提升困難,系統架構已經朝著多顆多核的架構上迅猛發展,如8路CPU的服務器也已經有一定的使用案例了.總之我們的硬件資源越來越豐富,而本文所講的並行查詢查詢主要是針對上面敘述的多個CPU協同工作,用以提升SQL查詢中的CPU-BOUND響應時間.(雖然在並行掃描(SCAN)的時候實際中同樣可以提升查詢的響應時間,但這我們就不細述了)

SQL Server關於”任務”的相關知–Schedulers,Tasks,Workers. Schedulers是指SQL Server中SQLOS識別到的硬件環境中的邏輯CPU,它是管理SQL Server計算工作的基本單位,它提供”線程”(workers)用於分配相應的”CPU”資源用於計算.

Tasks實際就是SQL Server中的工作單元,本質上就是一個函數指針(C++),用於指向需要執行的代碼.比如LazyWriter實際上就是去調用相應的Function(sqlmin!Lazywriter()).Workers 如果說Tasks是指向工作的地方,那麽Workers是處理相應的工作,它綁定到Windows線程的方式用於計算.OK,現在說一條SQL請求SQL Request=Task+Worker應該能理解了吧.為了加深理解,我們可以看圖1-1

1_1
圖1-1

最終回到我們的並行查詢,實際就是多個tasks在多個schedulers上同時運行,提升響應速度!

關於SQLOS,微軟在SQL Server 2005年引入,可以說是個重大的突破,就像Michael Stonebraker(2014圖靈獎得主)老爺子的早年Paper” Operating system Support for database Management”中敘述的那樣,SQLOS,比OS更懂數據庫,感興趣的朋友自行搜索下.限於篇幅這裏就不細深入SQLOS了,給出一張簡單架構圖大家感受下J 如圖1-2

1_2
圖1-2

OK準備知識完畢,我們進入並行查詢執行吧

並行相關概念

串行執行計劃–在了解並行執行之前,我們先了解下串行執行計劃的相關知識.其實很簡單,關於執行計劃本身這裏就不介紹了,只是介紹下與本文相關重要元素.

串行執行計劃實際就是由單個線程(thread)執行完成,單個執行上下文(execution context)

執行上下文就是指執行計劃中用於執行的一些信息,如對象ID,如執行計劃中使用到的臨時表等等.在執行中實際上就是單個(核)CPU在工作,如圖2-1
2_1
圖2-1

而並行執行計劃,顧名思義,就是多個(核)CPU在同時工作,用於提升CPU-Bound的響應時間,對應串行,它有多個線程,多個執行上下文,但也會消耗更多的資源.但對於磁盤IO,SQL Server認為是木有幫助的,我們通過一個簡單的實例看下:

註:文章中使用的AdventureWorks,網上可以自行搜索下載

—串行執行

select COUNT(*)

from dbo.bigTransactionHistory option(maxdop 1)

–並行執行

select COUNT(*)

from dbo.bigTransactionHistory option(maxdop 2)

通過觀察上面兩條簡單語句的執行計劃可以發現,在預估Subtree cost中 (資源消耗量)實際上單CPU與雙CPU相比只是CPU預估減半,IO預估不變.如圖2-1-a

2_1_a
圖2-1-a

讓我們真正的進入並行執行計劃,每個並行執行計劃都有一個主的交換操作(root exchange),即圖形執行計劃中最左面的Gather stream運算符(後面會講到)(SQL Server有圖形執行計劃,不小小夥伴很羨慕吧J)而所有的並行執行計劃都會有一個固定的串行部分—即最左邊Gather stream運算符中所有靠左的部分(包含Gather中消費者,後面會講到生產-消費模型)的所有操作,他是由主線程Thread Zero控制,同時它的執行上下文也是context zero,如圖2-2所示

2_2
圖2-2

而並行區域,顧名思義就是root exchange所有靠右的部分,而並行部分又有可能有多個分支

(Branches),每個Branch都可以同時執行(分支有自己的tasks),分支自身可以是並行,也可以是串行.但分支不會使用主線程thread zero.關於分支大家可以用如下語句自己看下相關執行計劃屬性(SQL Server 2012版本及之後版本可以顯現) 如圖2-3所示

如圖2-3-2,我的最大並行度設置為4,有三個branches,而這裏我使用的線程數就是

4*3=12,再加上一個主線程 thread zero 這個並行查詢我所使用的線程總數為13個.

MySQL 12345678910111213 select a.productid,count_big(*) as rows from dbo.bigproduct as inner  join dbo.bigtransactionhistory as on a.productid=b.productid where a.ProductID between  1000 and 5000 group by a.productid order by a.productid

2_3_1

圖2-3-1

2_3_2
圖2-3-2

而並行和串行的區別聯系,大家可以理解成下圖2-4

主線程在串行中實際就是他的執行線程

2_4
圖2-4

圖2-3中,並行的表掃描後聚合,實際上是等於兩個串行的表掃描聚合.這個提到並行表掃描table scan(range scan)就稍微展開下:在SQL Server 2005及以前版本中並行掃描實際上是

” parallel page supplier”及每個線程掃描的單位是數據頁,掃描多少有數據頁中含有的數據行多少決定,而在SQL Server 2008及以後是”Range Enumerators” 每個線程掃描的數據實際上是由數據的區間分布決定的,至此也就有了我們在08及以後版本中經常看到的“access_methods_dataset_parent”閂鎖等待,你可能會疑問怎麽高版本還帶來新問題,實際上在 ” parallel page supplier”中的問題也是不少的,比如在快照隔離級別下的數據頁掃描確認問題等等,總得來說還是更高效了.這裏需要大家註意的是並行掃描只支持前滾掃描(forward),不支持反向掃描(backward)感興趣的朋友可以根據下面代碼自行測試.

/*************************並行掃描相關測試*********************************/

—-並行掃描中只有前滾掃描才可以並行

MySQL 12345678910111213141516171819202122232425 USE [AdventureWorks2008R2] GO select color,COUNT(1) from [bigProduct] group by Color option(querytraceon 8649)--- Parallel scan only forward go CREATE NONCLUSTERED INDEX [inx_color] ON [dbo].[bigProduct] (          [Color] desc----asc can parallel desc can not )WITH ( DROP_EXISTING = ON) ON [PRIMARY] ---修改索引排序規則(asc,desc) GO select color,COUNT(1) from [bigProduct] group by Color option(querytraceon 8649)--- Parallel scan only forward

/*************************並行掃描相關測試*********************************/

看到這裏不少朋友可能有疑惑了,上文中又是串行,又是並行,又是多tasks,到底什麽時候用串行,什麽時候並行,用多少個tasks啊,實際上SQL Server實例級有兩個設置:並行閾值”cost threshold for parallelism” 即當Subtree cost(前面提到的估計資源消耗)大於設定值時優化器才會觸發並行優化,進而可能生成並行執行計劃.二:最大並行度(max degree of parallelism)用於設置分支(branches)中到底可以多少個CPU同時工作.這裏給大家畫個簡單的圖,大家就一目了然了.如圖2-4

2_5
圖2-5

至此,並行相關的基本概念已經介紹完畢,接下來讓我們深入並行..

Exchanges

顧名思義,就是交換,在並行裏指的是threads間的數據交換,這也是在只有並行執行的情況下才會有的操作符.具體到SQL Server中有三種exchanges 操作,分別為Gather Streams, Repartition Streams,以及Distribute Streams其對應起到的作用就是聚集,重定向,分發Threads間的數據,操作符如圖3-1所示

3_1
圖3-1

而實際上上述運算符每一個都是兩個運算符的”合集”這裏就是我們之前提到的生產者與消費者操作.操作符中右邊為生產者,將生成的數據放入packets中,而左邊為消費者,從packets中將數據取出.如圖3-2所示

3_2_1
圖3-2-1

3_2_2
圖3-2-2

這裏解釋下我們在SQL Server中常見的CXPACKET等待,不少同學都將這個等待看做並行中某些線程工作快,某些線程工作慢而產生的差異,這個對,但說法不專業,實際上根據生產者消費者模型來看分析是:

CXPACKET Waits=Class eXchange PACKET

針對生產者:所有的 Buffer packets 都已經被填滿,無法繼續生產(填充)

針對消費者:所有的Buffer packets都是空的,沒有數據可以消費

在生產者與消費者的模型中,數據是通過一定規則由生產者流動到消費者那裏,在SQL Server有如下5種規則

Broadcast:廣播,當數據量較小時將生產者的所有數據都廣播到所有的消費者中.阿裏的朋友在分布式中間件中小表廣播應該有不少應用吧J

Hash:通過哈希函數將制定的數據一個或多個欄位哈希化(簡單的如取模),根據不同的值填充到不同的Buffer packets中供消費者使用.

Round Robin 顧名思義,將數據順序逐條地添加到每個Buffer packets中.

Demand 之前的都是發送數據,而這個是消費者從生產者中拉數據,如某個消費者拉某個常量的數據,這個只在分區表中采用.

Range 顧名思義,根據數據中某些欄位的分布,分別填充到不同的Buffer packets中,這個一般在並行索引,統計信息重建時采用.

有了生產者和消費者的數據使用方式,你可能覺得還差點什麽吧?沒錯,數據是否是有序的呢,SQL Server中exchange分別Merge Exchange 和Non-Merge Exchange,分別對應數據在exchage時是否要求有序,當然大家也都知道了有序的成本Merge Exchange明顯高於無序
如圖3-3所示

3_3
圖3-3

Parallel joins

最後我們來談談SQL Server中的並行Join.SQL Server中對於三種基本join: nested loop join ,merge join, hash Join都支持,我們分別說明下他們的優缺點,在今後的並行優化時,你可能用到.在這裏我就不復述三類join鏈接的基本算法了,不懂的同學wikipedia下

Parallel merge join 如圖4-1

將參與join的key(兩個表)都進行hash化,然後同時進行匹配.

並行merge join幾乎無優點,缺點倒是不少,首先是需要merge exchange,其次增加CPU本身對性能幫助實際不大(參考相應算法),而且merge join還會增加並行死鎖的幾率.所以實際生產中我們還是應盡量避開merge join.

4_1
圖4-1

Parallel hash join

Build階段,如果數據量小,所有broadcast到所有threads中 如圖4-2-1,否則就將join key 哈希化,進行匹配,如圖4-2-2

這裏應註意parallel hash join是Non-merge exchanges,且隨著CPU的增加,性能是線性擴展的(具體參考相應算法),但在parallel hash join中應註意可能由於統計信息問題,復雜join導致的hash join在構建,探測階段都有可能因為內存不足而溢出的現象,從而拖慢查詢.關於溢出可以使用跟蹤,擴展事件捕捉等.

4_2_1
圖4-2-1

4_2_2
圖4-2-2

Parallel nested loop join

外表多個threads同時運行(如掃描數據),而內表則在每個thread上串行同時進行匹配.

Parallel nested loop join在實際生產中可能為我們解決許多一些棘手問題,比如他會減少並行計劃中的exchange使用,使用更少的內存等等.但也應註意可能由於數據分布傾斜,nested loop預讀等情形導致的性能提升有限,而消耗反而相比串行提高等問題.而且SQL Server的優化器本身是”不喜歡並行循環嵌套的”,有時我們需要特定的寫法才能實現他.如圖4-3

4_3
圖4-3

最後我們再提下Bitmap過濾吧,SQL Server是沒有位圖索引的,這個也頗為詬病,但實際SQL在執行時是有可能用到位圖過濾的.

簡單說下SQL Server位圖過濾實現方式(具體大家也可以wikipedia bloom filter)

實現方式:通過構建一個長度X的位數組(bit array)(所有位為0),將要匹配的集合通過哈希函數映射到位數組中的相應點中(相應位為1),當判斷一個值是否存在時找bit array中對應位是否為1就可以了.這個過程由SQL Server內部自己完成. 如圖4-4-1,圖4-4-2我將一個現有數組哈希化,然後在其中搜索 ”悟空..”是否在數組中

4_4_1
圖4-4-1

4_4_2
圖4-4-2

好了,SQL Server 相關的並行知識就給大家介紹這麽多吧,後面有時間給大家帶來相關的實踐應用.

1 2 收藏 評論
Tags: 數據庫系統 摩爾定律 互聯網 服務器 Oracle

文章來源:


ads
ads

相關文章
ads

相關文章

ad