SQL Server 性能調優(一)——從等待狀態判斷系統資源瓶頸

通過DMV查看當時SQL SERVER所有任務的狀態(sleeping、runnable或running)

2005、2008提供了以下三個視圖工詳細查詢:

DMV

用處

Sys.dm_exec_requests

返回有關在SQL Server中執行的每個請求的信息,包括當前的等待狀態

Sys.dm_exec_sessions

對於每個通過身份驗證的會話都返回相應的一行。此時圖是服務器範圍的視圖。此視圖首先可以查到服務器負荷

Sys.dm_exec_connections

返回與SQL Server 實例建立的連接有關的信息以及每個連接的詳細信息

Sys.sysprocesses是爲了向後兼容,所以建議使用以上3個DMV。

另外還有一個DMV:sys.dm_os_wait_stats可以返回從SQL Server啓動以來所有等待狀態的等待數和等待時間。是個累積值。

1、 LCK_XX類型:

如果SQL Server經常有阻塞發生,會經常看到以“LCK_”開頭的等待狀態:

等待狀態

說明

LCK_M_BU

正在等待獲取大容量更新鎖(BU)

LCK_M_IS

等待獲取意向共享鎖(IS)

LCK_M_IU

等待獲取意向更新鎖(IU)

LCK_M_IX

等待意向排它鎖(IX)

LCK_M_RIn_NL

等待獲取當前鍵值上的NULL鎖以及當前剪和上一個鍵之間的插入範圍鎖

LCK_M_RIn_S

等待獲取當前鍵值上的共享鎖以及當前鍵和上一個鍵之間的插入範圍鎖

LCK_M_RIn_U

等待獲取當前鍵值上的更新鎖以及當前鍵和上一個鍵之間的插入範圍鎖

LCK_M_RIn_X

等待獲取當前鍵值上的排他鎖以及當前鍵和上一個鍵之間的插入範圍鎖

LCK_M_RS_S

等待獲取當前鍵值上的共享鎖以及當前鍵和上一個鍵之間的共享範圍鎖

LCK_M_RS_U

等待獲取當前鍵值上的更新鎖以及當前鍵和上一個鍵之間的共享範圍鎖

LCK_M_RX_S

等待獲取當前鍵值上的共享鎖以及當前鍵和上一個鍵之間的排他範圍鎖

LCK_M_RX_S

等待獲取當前鍵值上的共享鎖以及當前鍵和上一個鍵之間的排他範圍鎖

LCK_M_RX_U

等待獲取當前鍵值上的更新鎖以及當前鍵和上一個鍵之間的排他範圍鎖

LCK_M_RX_X

等待獲取當前鍵值上的排他鎖以及當前鍵和上一個鍵之間的排他範圍鎖

LCK_M_S

等待獲取共享鎖

LCK_M_SCH_M

等待架構修改鎖

LCK_M_SCH_S

等待獲取架構共享鎖

LCK_M_SIU

等待共享意向更新鎖

LCK_M_SIX

等待獲取共享意向排他鎖

LCK_M_U

等待更新鎖

LCK_M_UIX

等待更新意向排他鎖

LCK_M_X

等待排他鎖

2、 PAGEIOLATCH_X與WRITELOG:

在緩存池中的數據頁面,爲了同步多用戶併發,SQL Server會對內存的頁面加鎖。不同的是,加的是latch(輕量級的鎖),而不是lock。

如果發生PAGEIOLATCH類型的等待時,SQL Server一定是在等待某個I/O動作的完成。如果經常出現這類等待,說明磁盤速度不能滿足要求,已經成爲SQL Server的瓶頸。

PAGEIOLATCH_X最常見的分兩大類:PAGEIOLATCH_SH和PAGEIOLATCH_EX,PAGEIOLATCH_SH經常發生在用戶正想要訪問一個數據頁面,而同時SQL Server卻要把頁面從磁盤讀往內存。說明內存不夠大,觸發了SQL Server做了很多讀取頁面的工作,引發了磁盤讀的瓶頸。此時是內存有瓶頸。磁盤只是內存壓力的副產品。

PAGEIOLATCH_EX經常發生在用戶對數據頁面做了修改。SQL Server要向磁盤迴寫的時候。意味着寫的速度跟不上。這和內存沒直接關係。

WRITELOG和磁盤有關的另一個等待狀態,正在等待寫日誌記錄,意味着寫入速度也明顯跟不上。

3、 PAGELATCH_X:SQLServer爲了解決在插入數據時,到了物理層的插入衝突,所以引入了另一類頁面上的latch:PAGELATCH,當一個任務要修改頁面時,它必須先申請一個EX的latch。只有得到這個,才能修改頁面的內容。由於數據頁的修改都是在內存中完成,所以時間應該非常短,可以忽略不計。而PAGELATCH只是在修改過程中才出現,所以生存週期應該很短,如果出現了,說明:1、SQLServer沒有明顯的內存和磁盤瓶頸。2、應用程序發來大量的併發語句在修改同一張表。而設計及用戶業務邏輯使得這些修改都集中在同一個頁面,或者數量不多的幾個頁面,成爲Hot Page,通常在OLTP系統上出現比較多。3、這種瓶頸無法通過提高硬件配置解決,只能通過修改表設計或者業務邏輯,讓修改分散,提高併發性。

對於Hot page的緩解方法:

(1)、換一個數據列建聚集索引,而不要在Identity的字段上,同一時間插入有機會分散到不同的頁面上。

(2)、如果一定要在Identity的字段上建聚集索引,建議在其他某個列上建若干個分區。

4、 Tempdb上的PAGELATCH:

數據庫不僅在數據頁面修改的時候加latch,在數據文件的系統頁面上,例如SGAM、PFS和GAM頁面發生修改的時候,也會加latch。有時候也會成爲系統瓶頸。

在創建新表需要分配空間時,SQLServer同時要修改SGAM、PFS和GAM頁面,把已分配的頁面標誌成已使用,所以這些頁面都會有所修改。但在tempdb中,這種操作會併發、反覆。數據頁的hot能通過調整表設計來緩解。對此的解決方法:

1、 建立與cpu數量相同的tempdb文件,並且大小要相同,這樣能平均分配壓力。

2、 嚴格防止tempdb空間用盡。防止自動增長時把其中一個文件增長,破壞平均分配。

3、 可以使用sp_helpfile來查看文件信息。

5、 其他資源等待:

1、 LATCH_X:

(1)、某個先前的任務出現了訪問越界異常,SQLServer強制終止了任務,但是沒有完全將它申請的資源釋放乾淨。使其成爲孤兒。後面的資源就被阻塞。只要打開SQLServer日誌文件(errorlog),看看有沒有出現過Access Violation問題,但是一般無法從用戶層面一般無法解決,只有重啓服務器才能解決。

(2)、同時發生其他資源瓶頸,如內存、線程調用、磁盤等,而latch等待只是一個衍生的等待。

(3)、當某個數據文件空間用盡,做自動增長的時候,同一個時間點只能有一個用戶任務可以做文件自動增長動作,其他任務必須等待。

(4)、在一些特殊情況下,有可能是SQLServer自己沒有處理好併發同步,沒有使用比較優化的算法,使得用戶比較容易遇到等待,一些補丁就曾修復過這類問題。

一般等待都是由其他問題衍生出來,首先要檢查SQLServer是否健康運行。是否有出現過任何異常。是否有其他資源瓶頸。

2、 ASYNC_NETWORK_IO(NETWORK_IO:2000的叫法):

此等待狀態出現在SQLServer已經把數據準備好,但是網絡沒有足夠的發送速度跟上,所以SQLServer的數據沒地方存放。

(1) 出現這種情況一般不是數據庫的問題,調整數據庫配置不會有大的幫助。

(2) 網絡層的瓶頸當然是一個可能的原因:對此要考慮是否真有必要返回那麼多數據?

(3) 應用程序端的性能問題,也會導致SQLServer裏的ASYNC_NETWORK_IO等待。如果見到了這個類型的等待,就要檢查應用程序的健康狀況,也要檢查應用是否有必要想SQLServer申請這麼大的結果集。

3、 和內存有關的等待狀態:

當用戶任務申請內存暫時申請不到的時候,會出現一些特殊的等待狀態:

COEMTHREAD/SOS_RESERVEDMEMBLOCKLIST/RESOURCE_SEMAPHORE_QUERY_COMPLIE

如果在DMV上看到這些狀態,就要確認SQLServer是否存在內存瓶頸。

4、 SQLTRACE_X:

對於繁忙的SQLServer,開啓SQL Trace會產生負面影響。如果出現這種等待,除非迫不得已,不然應該立刻停止蒐集SQL Trace

6、 最後一道瓶頸:許多任務處於runnable狀態:

如果出現這種狀態,證明很多任務可以運行但沒在運行。

Sys.dm_exec_requests/sys.sysprocesses的status列,反映了當前所有任務的狀態,如果看到好多狀態是runnable,那就要嚴肅對待,正常的SQLServer哪怕非常忙,也不應該經常看到runnable,連running的狀態都不應該很多。

如果沒有報17883/17884之類的警告,出現非常多的runnable任務可能有兩種原因:

(1)、SQLServer CPU使用率接近100%,真的沒有足夠的cpu來及時處理用戶的併發任務。此時應該優化最耗CPU資源的語句或者應用,或者加CPU

(2)、SQLServer CPU使用率並不高,小於50%。這時檢查sys.dm_exec_requests的task_state列,會發現很多runnable狀態。因爲SQLServer除了lock和latch之外,還有一種更輕量級的同步資源:spin lock(自旋鎖)。自旋:一些不會發生長時間等待的同步資源,SQLServer會選擇讓線程在cpu上稍微等待一下,而不會將cpu資源讓出來。

可以使用DBCC SQLPERF(SPINLOCKSTATS)查看。

在2005上的64位SQLServer,當內存比較充裕時,會緩存很多執行計劃,同事緩存很多執行計劃安全上下文。在memory clerk裏,用TokenAndPermUserStore表示,當這段內存比較大時,併發用戶會容易遇到一種叫MUTEX的自旋鎖。可以參考:http://suppot.microsoft.com/kb/927396。這種問題只在安全上下文緩存得太多時才容易發生,所以定期執行一下以下語句有效防止,而且對系統整體性能也沒什麼壞的影響:

DBCC FREESYSTEMCACHE(TokenAndPermUserStore)

也可以以-T4618和-T4610啓動SQLServer,讓SQLServer使用另一種緩存管理機制。

據說2008已經改進,不容易出現自旋鎖。

7、 小結:

用戶請求的什麼週期:

1、 客戶端向SQLServer發出請求指令,經過網絡層,SQLServer接收到。

在這一步中,如果指令比較長,或者比較多,會影響SQLServer接受的速度。

2、 SQLServer對收到的指令進行語法、語義檢查,編譯,生成新的執行計劃,或者找到緩存的計劃重用:這一步耗費資源的種類比較多:

l CPU:做檢查、編譯、生成計劃都需要計算,這一步耗費CPU資源比較多,尤其是指令複雜的時候。

l 內存:對於非常長的IN子句或者由幾萬、幾十萬語句組成,要花費非常大的內存,主要使用stolen內存,對於32位系統來說是很緊張的。一般會出現這些等待情況:CMEMTHREAD/SOS_RESERVEDMEMBLOCKLIST/RESOURCE_SEMAPHORE_QUERY_COMPILE,或者701錯誤。

l 表上的架構鎖(schema lock):在編譯時,要防止對該架構進行修改。如果併發很高,那麼會產生阻塞。

l 在SQLServer確認是否有線程的執行計劃可用時,要在內存中進行搜索。可能會產生自旋鎖。

3、 運行指令:

在等到執行計劃之後,就進入運行階段,用到的資源最多。在這一步要做很多事情:

(1) 、SQLServer首先爲指令的運行申請內存。

如果同時需要執行很多指令,可能會在內存上遇到困難,通常會見到:RESOURCE_SEMAPHORE_開頭的等待狀態。

(2) 、如果發現要訪問的數據不在內存中。

要講數據從磁盤讀到內存,如果發現內存沒有足夠的空閒頁面存放所有數據,還要做內存整理和paging動作,騰出足夠的空間放數據。通常簡單的等待狀態是:PAGEIOLATCH_X。

(3) 、按執行計劃,掃描或者seek內存中的數據頁面,講執行需要處理的記錄找出來。這一步需要申請各種各樣的鎖,以實現事務隔離。通常會引起阻塞,以LCK_開頭的那些。

(4) 、指令可能還要做一些連接或者計算工作(sum、max、sort等)

這一步主要使用CPU。

(5) 、根據指令內容、執行計劃和數據量,SQLServer可能還會在tempdb創建一些對象,存放臨時表、表變量,幫助做join、sort等。

此時有可能出現tempdb瓶頸。

(6) 、如果指令需要修改數據記錄,SQLServer會修改內存緩衝區裏的頁面內容。

由於對象在內存中,不會觸發磁盤寫入,但由於修改同一頁面,容易導致PAGELATCH_X的等待狀態。

(7) 、如果指令發生數據修改,在提交事務之前,SQLServer必須將相應的日誌記錄按照順序寫入日誌文件。如果瞬間日誌量太大,會出現WRITELOG的等待狀態。

(8) 、將結果集返回給客戶端:得到結果後,SQLServer會把結果集放到輸出緩存中,等客戶端把結果集全部取走。指令才結束。如果數據集太大,會導致網絡交互太多。此時容易出現:ASYNC_NETWORK_IO等待狀態。

以上的動作都要在SQLOS中首先得到一個Worker/thread,然後還要排上scheduler,在CPU上運行。

l SQLServer所有的Worker都在忙自己的事情,就會等待,可以看到等待狀態是0x46(UMSTHREAD)。而sys.dm_os_schedulers.work_queue_count的值會不等於0

l 成功拿到worker,但在scheduler又要等待其他Worker,這時看到狀態是runnable,而sys.dm_os_schedulers.runnable_tasks_count>1。

l 拿到scheduler,進入running狀態,如果非常耗CPU,會出現cpu使用率高的現象。

l 遇到性能問題,查看sys.dm_exec_requests這類DMV對找到問題很有幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章