一、概述
在數據庫應用中,速度是一個永恆的話題。有許多因素會影響數據庫的性能表現,例如:操作系統,硬件方面的因素,如內存和磁盤空間,訪問數據庫的應用軟件。除此之外,數據庫本身的設計也是一個影響性能的重要因素。

本文要討論的是我們可以採取哪些措施提高SQL Server數據庫的性能。討論的焦點主要集中在SQL Server 2000為視圖創建索引的能力,以及如何使用Index Tuning Wizard(ITW,索引調整嚮導)優化索引。另外,我們還要討論如何確保查詢充分地利用了索引以及數據庫統計信息。

性能問題應該在數據庫設計的初始階段就開始考慮。不過,即使在數據庫正式開始運行之後,我們仍舊可以進行一些修改,這些修改將顯著地影響數據庫的性能表現。索引是一種優化數據查詢和排序操作的數據庫實體,正確配置的索引能夠使數據庫查詢或更新數據所需要的時間發生巨大的變化,ITW能夠幫助我們確定如何在數據庫中配置索引以獲得最佳的性能。

我們可以讓ITW根據指定的Workload(工作負荷)推薦最佳的數據庫索引配置。Workload是保存到外部文件的SQL腳本或跟蹤結果。ITW的建議是根據給定Workload而提出的最優化建議,因此事先準備合適的基礎數據非常重要。

為ITW創建工作負荷文件最簡單、最全面的方法或許應該是保存由SQL Profiler創建的跟蹤。SQL Profiler是自SQL Server 7.0開始提供的新工具。它能夠用指定的過濾器和條件,記錄服務器的活動情況。使用SQL Profiler為ITW創建跟蹤時,應當確保跟蹤已經記錄了典型的數據庫活動。換句話說,應當選擇一個數據庫負載不是特別繁重、也不是特別輕鬆的時段進行跟蹤。至於跟蹤要運行多少長時間,這由系統本身的特點決定。有些時候,我們可能只需跟蹤數小時就可以得到系統典型活動情況的記錄;有些時候,我們可能要讓跟蹤持續幾天,才能記錄下數據庫中所有典型的活動情況。

二、索引調整嚮導
準備好工作負荷文件之後,我們就可以在Enterprise Manager的樹形視圖中選擇服務器啟動ITW。從Tools菜單選擇Wizards,在樹形視圖中找到Management節點,選擇Index Tuning Wizard,此時我們就可以看到ITW的歡迎屏幕。

ITW的第二個屏幕讓我們指定要分析的是哪一個服務器和數據庫。在這個屏幕上,我們還有另外兩個選項:Keep All Existing Indexes(保留現有索引),Perform Thorough Analyses(進行完全分析)。清除Keep All Existing Indexes選項使得ITW能夠提出最優索引建議,但此時ITW可能建議刪除或者修改現有的某些索引。如果你不想修改現有的索引,請保留這個選項的選中狀態。選中Perform Thorough Analyses選項使得ITW進行最廣泛、深入的分析。雖然進行完全分析可能提高分析結果的質量,但它一般需要較長的時間才能完成;而且完全分析運行時,它很可能導致服務器負載過重。由於這些原因,如果你需要執行完全分析,那麼最好在測試服務器上進行,或者在正式提供服務的機器上,選擇一個比較空閒的時段進行。

ITW的第三個屏幕讓我們指定對哪一個workload進行分析。如果你使用的是SQL Profiler創建的文件,請選擇My Workload File選項按鈕,然後在文件對話框中找到以前保存的跟蹤文件。在這個屏幕中,點擊Advanced Options命令按鈕可以設置一些高級選項。這些選項包括:被推薦的索引可以使用的最大磁盤空間總量,工作負荷文件中查詢取樣的最大數量。

在第四個屏幕中,我們可以指定ITW應該對哪個或者哪些表的索引提出建議。只選擇那些相關的表有利於節省時間,而且它有助於我們把注意力集中到特定的問題之上。不過,如果要讓ITW對整個數據庫的優化提出建議,我們應該選中數據庫裡面所有的表。

ITW的下一個屏幕根據我們設定的條件,顯示出它對索引配置的建議(參見圖1)。我們可以選擇立即執行它提出的建議,或者計劃在以後執行,或者把執行腳本保存到外部文件。
ITW不會對主鍵或者其他唯一性索引提出建議,也不會對系統表的索引提出建議。ITW的其他局限還包括:在給定的工作負荷中,它分析的索引不能超過32767個;不能對SQL Server 6.5或者更早版本創建的數據庫提出索引建議。

注意,ITW是以用戶所提供數據的樣本為基礎提出索引配置建議。由於這個原因,你可能會發現:如果讓ITW對同一個工作負荷分析多次,它可能會提出多種不同的索引配置建議。如果ITW不能提出任何建議,它可能是由於下面兩種原因之一造成:第一,與數據庫中現有的索引配置方案相比,ITW無法提出任何能夠進一步提高性能的索引建議;第二;取樣的表裡面沒有足夠的數據,無法確定一個合適的索引配置方案。

三、視圖索引
SQL Server 2000企業版除了能夠創建表的索引,它還能夠創建視圖的索引。假設我們對Pubs數據庫中每一份訂單的銷售總量感興趣。下面的代碼在Pubs數據庫中創建一個名為Quantity_Totals的視圖,該視圖除了提供上述信息之外,還提供了訂單所包含項目的總數:

Use Pubs GO CREATE VIEW Quantity_Totals with SCHEMABINDING AS SELECT ord_num, Total_Quantity = Sum(qty), Total_Items = Count_Big(*) FROM dbo.sales GROUP BY ord_num

COUNT_BIG是SQL Server 2000提供的一個新函數,它的功能與COUNT函數相同。COUNT_BIG和COUNT的不同之處在於,COUNT_BIG返回值是bigint類型,而COUNT返回值是int類型。任何包含GROUP BY子句的視圖,如果要使用索引就必須包含COUNT_BIG函數。我們可以用SCHEMABINDING選項創建包含索引的視圖。SCHEMABINDING選項是SQL Server 2000的新功能,如果我們指定了SCHEMABINDING選項,視圖將被綁定到其基表的模式。

如果視圖不包含索引,則數據庫中不保存視圖返回的結果集。有的時候,我們可能要創建涉及大量記錄或必須進行複雜計算的視圖,比如要進行聚合分組處理或多重連接操作。如果每次引用這些視圖的時候讓SQL Server重新生成結果集,數據庫開銷將非常大。

視圖的索引與表的索引在作用方式上非常相似。與表一樣,視圖可以有一個集簇索引(Clustered Index)和多個非集簇索引。然而,在創建任何非集簇索引之前,我們必須先為視圖創建一個唯一性的集簇索引。如果我們創建了視圖的集簇索引,數據庫將永久保存視圖的結果集。雖然創建索引時所保存的結果集只反映當時的數據狀態,但任何對基表數據的修改都將自動反應到這個結果集之中。

就像為表創建索引一樣,我們可以用CREATE INDEX命令為視圖創建索引:

CREATE UNIQUE CLUSTERED INDEX PRIMARY_IDX on Quantity_Totals(ord_num)

上面的代碼為我們前面例子中創建的Quantity_Totals視圖創建了一個唯一性的集簇索引。創建視圖索引不僅能夠提高視圖的性能,而且有些時候性能的提高達到出乎意料的程度。一旦我們為視圖創建並保存了索引,即使對於那些沒有直接在FROM子句中引用該視圖的查詢,Query Optimizer(查詢優化器)也可能選擇使用該視圖索引來提高查詢速度。例如,下面這個SQL命令選擇出按照訂單編號分組的銷售數量累計:

SELECT ord_num, Sum(qty) FROM sales GROUP BY ord_num

  執行這個查詢時,Query Optimizer知道:在SQL Server為Quantity_Totals視圖創建的索引中,這個銷售數量的累計值已經存在。在這種情況下,Query Optimizer會作出這樣的判斷:如果使用為視圖創建的索引,查詢的效率將有很大的提高。

  在為視圖創建索引之前,你必須檢查視圖是否滿足創建視圖索引的各種條件。下表列出了這些條件中的一部分:

項目 條件
創建視圖 創建視圖的時候必須指定SCHEMABINDING選項。此外,創建視圖時ANSI_NULLS和QUOTED_IDENTIFIER必須設置成ON。
視圖引用的表 被視圖引用的表應該與視圖在同一個數據庫中。創建所有被視圖引用的表時,ANSI_NULLS必須設置成ON。視圖只能引用基表,不能引用其他視圖。
視圖的SQL命令 視圖所包含的SELECT命令不能使用UNION操作符,不能使用任何子查詢。另外,它不能包含DISTINCT和ORDER BY關鍵詞,不能使用MIN、MAX和AVG函數。列必須顯式引用,SELECT語句不能用*或者table_name.*的方式引用列。

四、影響查詢性能的因素
除了數據庫的物理設計之外,我們用來保存和提取數據的查詢命令的結構也會對性能產生重大影響。內存或者磁盤空間不足之類的硬件問題會降低查詢的效率;然而,Query Optimizer不能有效地利用索引或者統計信息也是導致查詢性能低劣的主要原因之一。

統計信息由關於列裡面數據分佈情況的信息構成。查詢優化器運用統計信息幫助確定執行查詢的最優方法。當我們為一個或者多個列創建索引時,SQL Server將自動生成這些索引列的統計數據。默認情況下,SQL Server的Auto Create Statistics數據庫選項設置成True。Auto Create Statistics設置成True的結果是,SQL Server同時為表裡面的其他列自動生成統計數據。

SQL Server除了生成初始的統計信息之外,它還會定期地更新這些信息。更新這些信息的頻繁程度,由列和索引數據的變化頻繁程度以及列和索引的數據規模決定。大多數時候,無論是生成初始的統計信息還是更新這些統計信息,SQL Server都能夠高效地完成,我們無需進行任何手工干預。但是,有些時候我們可能會發現,系統不能順利地為表生成必需的初始統計信息,或者這些統計信息更新不夠及時。

我們可以用DBCC SHOW_STATISTICS這個T-SQL命令查看索引列的當前統計信息。這個命令有兩個參數,第一個參數指出要查看的是哪一個表的統計信息,第二個參數是索引的名字。例如,如果我們在Query Analyzer(查詢分析器)中執行下面這個SQL命令,它將顯示出有關Pubs數據庫中authors表aunmind索引的統計信息:

DBCC SHOW_STATISTICS (authors, aunmind)

DBCC SHOW_STATISTICS命令返回的結果中包含了SQL Server最後一次更新統計信息的日期和時間,以及SQL Server用來計算統計信息的采樣記錄數。我們可以在Query Analyzer中通過圖形用戶界面管理非索引列的統計信息,具體操作方法是:啟動Query Analyzer,從Tools菜單選擇Manage Statistics;在Manage Statistics對話框(圖2)中選擇要管理哪個數據庫以及表或視圖的統計信息。

Query Analyzer把所有現有的統計信息放入屏幕底部的列表框。選中一個統計項目,點擊Delete或Upate按鈕就可以刪除或者更新統計信息。如果點擊New命令按鈕,我們將看到Create Statistic對話框。創建新的統計項目時,我們可以選擇的參數包括:要包含哪個或者哪些列,SQL Server生成統計信息時從這些列讀入取樣數據的百分比,是否要求SQL Server在必要時自動更新統計數據。允許SQL Server自動更新統計信息是一種比較好的選擇,因為SQL Server通常都能夠高效地完成這一任務,而手工完成卻非常麻煩。

除了用Query Analyzer提供的圖形用戶界面生成、更新統計數據之外,我們還可以用CREATE STATISTICS和UPDATE STATISTICS這些T-SQL命令來完成同樣的任務。

五、查詢執行計劃
要瞭解查詢是否充分利用了索引和統計信息,一種方法是使用Query Analyzer查看查詢的執行計劃。啟動Query Analyzer並裝入查詢,從Query菜單選擇Show Execution Plan、執行查詢。在查詢結果的下面,我們可以看到一個名為Execution Plan的卡式子窗口。點擊Execution Plan即可查看查詢的執行計劃。

另外,在不實際運行查詢的情況下,我們也可以查看執行計劃,這時的執行計劃是「期望中的執行計劃」。從Query菜單選擇Display Expected Execution Plan,我們就可以看到一個圖,它描述了一個估計的查詢執行計劃。這個圖顯示了Query Optimizer為執行查詢已經(或者準備)採取的措施。從各個步驟的詳細說明中,我們可以瞭解哪一個步驟最耗時、哪一個步驟佔用資源最多,以及Query Optimizer是否使用了索引。如果Query Optimizer發現某個表的統計信息已經丟失或者過期,它會把表的標題顯示成紅色。把鼠標停留到表示表的圖標上面,我們就可以從一個彈出式窗口中看到關於該步驟的更多說明,如圖3所示。SQL Profiler是一個幫助我們判斷哪一個查詢導致性能問題並需要進一步分析優化的優秀工具;SQL Profiler能夠通過記錄服務器的具體活動指出哪些查詢和SQL命令效率低下。

總而言之,數據庫性能優化涉及到相當廣泛的問題。單純地保證系統有正確的索引和統計信息,對於數據庫全面優化來說是不夠的。然而,它們是能夠顯著改善數據庫響應時間的重要措施。我們只要稍微花上一點時間,就可以利用SQL Server的工具精心調整查詢,使得查詢能夠充分利用索引和統計信息。