首先需要說明的是這篇文章的內容並不是如何調節SQL Server查詢性能的(有關這方面的內容能寫一本書),而是如何在SQL Server查詢性能的調節中利用SET STATISTICS IO和SET STATISTICS TIME這二條被經常忽略的Transact-SQL命令的。
從表面上看,查詢性能的調節是一件十分簡單的事。從本質上講,我們希望查詢的運行速度能夠盡可能地快,無論是將查詢運行的時間從10分鐘縮減為1分鐘,還是將運行的時間從2秒鐘縮短為1秒種,我們最終的目標都是減少運行的時間。
盡管查詢性能調節困難的原因有許多,但這篇文章將只涉及其中的一個方面,其中最重要的原因是,每當使用環境發生變化時,就需要對性能進行調節,因此很難搞清楚到底需要如何調節查詢的性能。
如果象大多數用戶那樣在一台測試用的服務器上進行性能調查,其效果往往並不是十分地令人滿意,因為測試服務器的環境與實際應用的服務器環境並不完全相同。隨著對資源要求的不斷變化,SQL Server會自動地進行自我調節。
如果對這一點有疑問,可以在一台負載很大的服務器上反復地運行同一個查詢,在大多數情況下,執行查詢所使用的時間並不相同。當然,差距並不大,但其變化足以使性能的調節比它應有的程度要困難一些。
這到底是怎麼回事兒?是你的想法錯了還是在運行查詢時,服務器的負載過重?這是引起運行時間增加的原因嗎?盡管可以多次反復地運行查詢得到一個平均時間,但這樣作的工作量很大。我們需要用一種很科學的標准對每次測試時的性能進行比較。
測量服務器資源是解決查詢性能調節問題的關健
在服務器上執行查詢時,會用到許多種服務器資源。其中的一種資源是CPU的占用時間,假設數據庫沒有發生任何改變,反復地運行同一個查詢其CPU的占用時間將是十分接近的。在這裡,我指的不是一個查詢從運行開始到結束的時間,而是指運行這一查詢所需要的CPU資源數量,運行一個查詢所需要的時間與服務器的忙碌程度有關。
SQL Server需要的另一種資源是IO。無論何時運行查詢,SQL Server都必須從數據緩沖區中讀取數據(邏輯讀),如果所需要的數據沒有在緩沖區中,則需要到磁盤上讀取(物理讀)。
從討論中可以知道,一個查詢需要的CPU、IO資源越多,查詢運行的速度就越慢,因此,描述查詢性能調節任務的另一種方式是,應該以一種使用更少的CPU、IO資源的方式重寫查詢命令,如果能夠以這樣一種方式完成查詢,查詢的性能就會有所提高。
如果調節查詢性能的目的是讓它使用盡可能少的服務器資源,而不是查詢運行的時間最短,那麼就更容易測試你采取的措施是提高了查詢的性能還是降低了查詢的性能。尤其是在資源利用不斷變化的服務器上更是如此。首先,需要搞清楚在對查詢進行調節時,如何測試我們的服務器的資源使用情況。
又想起了SET STATISTICS IO和SET STATISTICS TIME
SQL Server很早以前就支持SET STATISTICS IO和SET STATISTICS TIME這二條Transact-SQL命令了,但由於其他一些原因,在調節查詢的性能時,許多DBA(數據為系統管理員)都忽略了它們,也許是它們不大吸引人吧。但不管是什麼原因,我們下面就會發現,它們在調節查詢性能方面還是很有用的。
有三種方式可以使用這二條命令:使用Transact-SQL命令行方式、使用Query Analyzer、在Query Analyzer中設置當前連接適當的連接屬性。在這篇文章中,我們將使用Transact-SQL命令行的方式演示它們的用法。
SET STATISTICS IO和SET STATISTICS TIME的作用象開關那樣,可以打開或關閉我們的查詢使用資源的各種報告信息。缺省狀態下,這些設置是關閉的。我們首先來看一個這些命令如何打開的例子,並看看它們會報告一些什麼樣的信息。
在開始我們的例子前,啟動Query Analyzer,並連接到一個SQL Server上。在本例中,我們將使用Northwind數據庫,並將它作為這個連接的缺省數據庫。
然後,運行下面的查詢:
SELECT * FROM [order details]
如果你沒有改動過order details這個表,這個查詢會返回2155個記錄。這是一個典型的結果,相信你已經在Query Analyzer中看到過好多次了。
現在我們來運行同一個查詢,不過這次在運行查詢之前,我們將首先運行SET STATISTICS IO和SET STATISTICS TIME命令。需要記住的是,這二個命令的打開只對當前的連接有效,當打開其中的一個或二個命令後,再關閉當前連接並打開一個新的連接後,就需要再次執行相應的命令。如果想關閉當前連接中的這二個命令,只要將原來命令中的ON換成OFF,再執行一次就可以了。
在開始我們的例子前,先運行下面的這二條命令(不要在正在使用的服務器上執行),這二條命令將清除SQL Server的數據和過程緩沖區,這樣能夠使我們在每次執行查詢時在同一個起點上,否則,每次執行查詢得到的結果就不具有可比性了:
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
輸入並運行下面的Transact-SQL命令:
SET STATISTICS IO ON
SET STATISTICS TIME ON
一旦上面的准備工作完成後,運行下面的查詢:
SELECT * FROM [order details]
如果同時運行上面所有的命令,你得到的輸出就會與我的不同,也就很難搞清楚到底發生了什麼事情。