上期我們講到LoadRunner性能測CPU瓶頸,這期我們講LoadRunner性能測試SQL server等待類型。
SQL Server等待類型
通常可能更多的去監控每個查詢執行步驟所消耗的時間,但其實這些還不夠,因為每個執行計劃在執行前可能需要等待,而這些等待的時間是被消耗了,沒有任何作用,所以如果能縮短等待時間顯然可以提高SQL Server的性能。
SQL等待類型
SQLServer通過
SQLOS(SQLServerOperatingSystem)
調度程序來管理用戶請求執行,SQLOS則通過SCHEDULER、WORKER、TASK等對任務進行調度和處理。
默認情況下調度程序的數量與伺服器中的邏輯CPU數量相同,即SCHEDULER個數與CPU個數相匹配,因為一個CPU某時刻只能運行一個調度程序,如果伺服器中包含2個CPU,則調試程序數量為2,如果是雙核的,那麼調度程序為4,如果是雙核且超線程的,則調度程序數量為8。只有拿到scheduler所有權的任務worker才能在這個邏輯CPU上運行。
使用以下查詢語句可以查詢到當前CPU數和SCHEDULER數。
SELECTcpu_count,scheduler_countFROMsys.dm_os_sys_info
結果如圖所示。
在調度程序內部,會話通常有三種狀態:
running、runnable和suspended,但會話只可能是這三種狀態中的一種,在任何時刻,調度程序上只能有一個會話處於running狀態,其它的會話都處於等待狀態,存儲在runnable隊列之中,停止執行並將某等待的會話狀態將改為suspended。會話三狀態圖如圖所示。
WORKER(又稱為WORKERTHREAD)是指工作線程,在一臺伺服器上,可以有多個工作線程。因為每一個工作線程要耗費資源,所以,SQLServer有一個最大工作線程數。
一個TASK(TASK是WORKER中運行最小的任務單元)進來,系統會給它分配一個工作線程進行處理,但是當所有的工作線程都在忙,而且已經達到了最大工作線程數,SQLServer就要等待,直到有一個忙的工作線程被釋放,最大工作線程數可以通過下面的查詢得到。SQLSERVER並不是一開始就把這些所有的工作線程都創建,而是依據需要而創建。
使用以下查詢語句可以查詢到當前最大工作線程數。
SELECTmax_workers_countFROMsys.dm_os_sys_info
Windows使用搶佔方式(pre-emptive)調度模型進行調度,意味著由調度程序決定運行某個任務的線程何時需要為另外一個任務讓路並切換出去,這種方式可以很好的運行在很多同等重要的不同服務的伺服器上,但對於運行SQLServer的伺服器來說,這種方式並不理想,因為一個SQLServer任務可能隨時被切換出去,而僅僅是為了給一個次要的Windows任務一些CPU的時間。SQLServer有著自身的調度程序,採用非搶佔式或協作模型,它依賴於所有線程在必須等待某事件時能產生處理時間,對於SQLServer來說這種模型是一種高效的模型,因為它可以判斷某個線程在何時需要處理器時間,即CPU時間。
TASK是由BATCH而來,一個連接,可以包含多個BATCH,而每個BATCH則可以分解成多個TASK,如下面某一個連接要做的事情,這個連接要做的有兩個BATCH,而每個BATCH,如以下查詢語句,可能會被分解成多個TASK
因為可以支持並行化查詢。具體BATCH怎麼分解成TASK,以及分解成多少個,則是由SQLServer內部進行處理。
INSERTINTOTABLE_BVALUES(『aaa』)
GO
SELECT*FROMTABLE_B
了解Connection、Batch、Task、Worker、Scheduler這些概念後,那麼,它們之間的關係如何呢?具體的關係如圖所示。
客戶端向伺服器發送請求時,會先建立一個連接
建立的連接數受max/minconnection兩個參數的影響,每個連接有一個相應的SPID,只要用戶沒有退出,或者沒有timeout,這個始終是存在的。
在每一個連接裡,可能會有多個batch,在一個連接裡,batch都是按順序的,只有上一個batch執行完了,才會執行下面一個batch。因為有很多連接,所以從SQLServer層面上看,同時會有很多個batch並行進行。
每一個batch,可能會分解成多個task以支持如並行查詢,這樣,在SQL層面上來看,同時會有很多個TASK。
SQLServer上,每一個CPU通常會對應一個Scheduler,有幾個額外的系統Scheduler,只是用來執行一些系統任務
對用戶來講,只需要關心UserScheduler就可以了,如果有4個CPU的話,那麼通常就會有4個UserScheduler。
每個Scheduler上,可以有多個worker對應,Worker是真正的執行單元,Scheduler(對CPU的封裝)是執行的地方
Worker的總數受maxworker_thread限制,每一個worker在創建的時候,自己需要申請2M內存空間,如果maxworker_thread為1024,並且那些worker全部創建的話,至少需要2G空間,所以過多的worker,會佔用很多系統資源。
在SQLServer中根據等待類型進行分類,通常可以分為三類:
Resourcewaits(資源等待)
當某個工作線程請求訪問某個不可用的資源(因為該資源正在由其他某個工作線程使用,或者該資源尚不可用)時,便會發生資源等待。資源等待的示例包括鎖等待、閂鎖等待、網絡等待以及磁碟I/O等待,鎖等待和閂鎖等待是指等待同步對象。
Queuewaits(隊列等待)
當工作線程空閒,等待分配工作時便會發生隊列等待,隊列等待通常發生在系統後臺任務(如監視死鎖以及清除已刪除的記錄等任務)中,這些任務將等待工作請求被放入工作隊列,即使沒有新數據包放入隊列,隊列等待也可能定期處於活動狀態。
Externalwaits(外部等待)
當SQLServer工作線程正在等待外部事件(如擴展存儲過程調用或連結伺服器查詢)完成時,便會發生外部等待。當診斷有防礙的問題時,請記住,外部等待不會始終表示工作線程處於空閒狀態,因為工作線程可能處於活動狀態且正在運行某些外部代碼。
資源等待,包括I/O、加鎖以及內存,是最為常見的等待。
如果出現下列任一情況,則SQLServer工作線程不可能處於等待狀態:
資源變得可用。
查詢非空。
外部進程完成。
儘管線程不再處於等待狀態,但是它並不表示立即開始運行,因為此類線程首先放入可運行工作線程的隊列中
並且必須等待量程在計劃程序中運行,在SQLServer2005中,等待時間計數器為bigint值。
使用以下查詢語句可以查看等待類型,如圖所示。
關於sys.dm_os_wait_stats欄位說明,見表。