在介紹Tempdb的併發問題前,先介紹幾個比較特殊的數據頁。 數據庫
PFS(Page Free Space),用於標識數據頁空間的使用狀況,以字節標識,能夠表示數據頁使用百分比,例如使用百分五十,百分八十,百分九十五以及徹底被使用,同時,還有一個字節位表示數據頁的類型,例如IAM頁等。一個PFS頁,能夠標識64MB的數據頁空間使用狀況。 服務器
GAM(Global Allocation Map),用於標識數據盤區(Extent)是否已分配,以位標識,當位爲0時,表示盤區還未分配,當位爲1時,表示盤區已經分配。一個GAM頁能夠標識大約4GB的數文件空間標識。 session
SGAM(Shared Global Allocation Map),用於標識混合數據盤區是否已分配,以位標識。混合空間中可能被存儲數據,也可能存儲索引。一個SGAM頁能夠標識大約4GB的數據文件混空間標識。 併發
Tempdb中,臨時表的數據特性如前面章節中介紹的,當會話中建立臨時表並初始化時,分配數據空間,在會話中刪除臨時表,或會話結束,便會將空間回收。數據的新增和刪除,都須要使用到數據頁,當數據頁的存儲空間大小發生變化時,PFS的字節標識值就須要發生變化。當這樣的操做頻率地發生在相同的一塊數據頁空間區域內時。如前面講閂鎖時所知道的,內在頁在更新時,是須要使用閂鎖來實現互斥的,當併發操做累積到特定的數值時,將會頻繁地出現閂鎖等待,此時有可能會形成服務器CPU使用率上升,甚至發生CPU滿負荷的狀況。 高併發
出於這樣的緣由,一般建議將Tempdb的數據文件個數增長到與邏輯CPU個數相同。這樣能夠達到數據分流的目的,避免在相同的數據區域內頻繁地擦寫數據。 工具
相同的狀況也有可能發生在GAM和SGAM頁上,只是GAM和SGAM要求臨時表的數據量較大。 oop
除了PFS,GAM以及SGAM幾個root頁的併發阻塞問題外,Tempdb還可能由於頻繁地建立臨時表而發生系統表阻塞的問題。例如,在高併發訪問的某個存儲過程當中,使用SELECT INTO的方式建立臨時表,當併發訪問足夠高,或者查詢語句須要消耗的時間比較長且有必定的併發量時,可能致使系統的元數據表,好比sys.objects視圖對應的系統元數據表sysschobjs或者sys.columns視圖對應的這些系統元數據表syscolpars,這些系統元數據也有可能因爲高併發以及較長的事務而產生大量的系統阻塞的狀況。解決這樣問題的方式即是,建立臨時表時,不該該將建立臨時表的語句包含在較長的事務當中。避免Tempdb的系統表被鎖住,引發別的進程沒法正常建立或操做臨時表。 測試
另外,在更高併發的狀況下,爲了達到Tempdb有更好的數據吞吐能力,建議將數據文件放在不一樣的磁盤上,以提升磁盤的吞吐量。 spa
接下來,咱們會使用到一個測試工具,工具名爲ostress。是微軟提供的SQL Server測試工具組件RML Utilities For SQL Server中的一個,你們能夠到微軟官網下載該工具,這個工具組件是免費的。 blog
Tempdb併發示例
如下連接爲64位工具下載地址:
http://www.microsoft.com/en-us/download/details.aspx?id=4511
如下是32位工具的下載地址:
http://www.microsoft.com/en-us/download/details.aspx?id=8161
下載完測試軟件,並安裝後,咱們須要在數據庫中,建立相應的存儲過程,存儲過程代碼如代碼清單9-5中所示,建立兩個存儲過程,usp_temp_table_test做爲子存儲過程,usp_loop_test_table_test循環調用它。
CREATE PROC dbo.usp_temp_table_test
AS
BEGIN
CREATE TABLE #table(c1 INT,c2 CHAR(5000));
DECLARE @i INT=1;
WHILE(@i<=10)
BEGIN
INSERT INTO #table (c1,c2)VALUES (@i,'test');
SET @i+=1;
END
END
GO
CREATE PROC dbo.usp_loop_temp_table_test
AS
BEGIN
SET NOCOUNT ON;
DECLARE @i INT=1;
WHILE(@i<100)
BEGIN
EXEC dbo.usp_temp_table_test;
SET @i+=1;
END
END
GO
代碼清單9-5 Tempdb併發阻塞測試
建立對應的代碼後,使用ostress模擬用戶併發的狀況,執行下面的Windows批處理指令,如代碼清單9-6中所示,使用ostress模擬300個併發執行咱們建立的存儲過程。
"C:\Program Files\Microsoft Corporation\RMLUtils\ostress.exe" -S(local)\SQL2012 -E -Q"exec [AdvantureWorks2008R2].dbo.usp_loop_temp_table_test;" -o"D:\output.txt" -n300
代碼清單9-6 執行ostress工具
在執行ostress時,使用動態管理視圖查看當前服務器內存中,Tempdb內存頁的閂鎖等待狀況,全縣下面的語句,查詢動態管理視圖sys.dm_os_waiting_tasks獲取相應的阻塞信息,代碼如代碼清單9-7中所示。
;WITH waiting_tasks
AS (SELECT session_id,
wait_type,
wait_duration_ms,
blocking_session_id,
resource_description,
PageID = CONVERT(INT,RIGHT(resource_description,LEN(resource_description)-CHARINDEX(':',resource_description,3)))
FROM sys.dm_os_waiting_tasks
WHERE wait_type LIKE 'PAGE%LATCH_%' AND resource_description LIKE '2:%')
SELECT session_id,
wait_type,
wait_duration_ms,
blocking_session_id,
resource_description,
ResourceType = CASE WHEN PageID=1 OR PageID%8088=0 THEN 'PFS Page'
WHEN PageID=2 OR PageID%511232=0 THEN 'GAM Page'
WHEN PageID=3 OR (PageID-1)%511232=0 THEN 'SGAM Page'
ELSE 'Not PFS, GAM, or SGAM page'
END
FROM waiting_tasks;
代碼清單9-7 查看當前tempdb的Latch狀況
經過查詢語句,能夠看到如圖9-5中所示,此時服務器絕大部分是PFS數據頁的閂鎖等待。
圖9-5 服務器的閂鎖等待
從執行結果上看到,300個併發任務中,有297個正在等待數據頁2:1:1,此處頁爲PFS數據頁,其等待類型爲PAGELATCH_UP類型。致使這樣的緣由這是由於Tempdb在實例中只有一個數據文件,高併發的狀況下,致使數據頁併發更新帶來的阻塞。
如何配置Tempdb能夠避免圖9-5中的問題,在前面小節中咱們已經有提到過了,提升併發的方法即是增長數據文件,將併發分開,避免對同一個文件進行操做。那麼配置多個文件須要注意些什麼事項呢?
SQL Server對於具備多個文件的數據庫在寫入數據時,數據庫引擎將按照各個數據文件的大小比例進行數據分配,所以,當對Tempdb配置多個文件時,要保持Tempdb的數據文件大小保持一致,這樣才能達到在存儲Tempdb數據時,能夠達到近乎平均使用和分配數據文件的做用,才能達到平均使用每一個文件中的PFS,GAM以及SGAM這些root數據頁的目的。