性能測試新手誤區(二):為什么我模擬的百萬測試數據是無效的?
測試環境的重要性無需多說,大家都知道測試環境要盡量的模擬生產環境,當然也包括數據。這樣測試的結果才會更加準確的反應真實的性能。就連開發過程,都已經開始在大數據量下加壓開發了。那么,關于測試數據,你了解多少呢?
通常說的測試數據可以分為兩類:
一是為了測試性能而準備的數據,這是用來模擬“壓力”的數據。也就是常說的數據量、歷史數據等。一般都會根據需求或者經驗很容易估算出來,比如案件年增長量為5%,去年數據量為100W,測試需要保證3年后系統仍可正常運行,那么就需要計算并模擬出3年后的總數據量,在這個基礎上進行測試。
二是用來輔助測試使用的數據。比如有一個對案件進行打分的功能,只有符合一定條件的案件才會出現在打分列表 中。那么我們要測這個打分的操作,首先就要保證有可用的案件,這就需要去生成測試數據,該數據可能一經使用就失效了(已經打過分就不能再打了)。這樣,每 次測試這個功能,就需要準備這樣一批數據。這里的測試數據,更多的是和測試流程有關,是為了能夠正常的進行測試,而不是涉及到性能的。
我們這里要說的是第一類,對性能測試結果產生直接影響的數據。
先看兩個小案例,涉及到了案件表(T_AJ)和法院編號列(N_FY)、立案日期列(D_LARQ)。案件表中模擬了一百萬測試數據,測試簡單的查詢操作,根據經驗,預期響應時間在2秒之內。
案例1. 查詢本院案件列表,相應的SQL如下:
select * from T_AJ
where N_FY=10
order by D_LARQ desc
經排查,生成的100W測試數據中,所有的N_FY列值都為10。這樣,最明顯的問題就是,查詢的結果集數量完全偏離了正常范圍。如果實際有 100家法院,正常分布下,每家法院只有1W的案件,但測試數據的FY只有一個值,通過這個查詢,查出了原來100家法院的數據。無論是在數據庫處理中 (如本例的排序),還是在程序的處理中(如展現或者是對數據做進一步處理),兩者的性能差異都是很顯著的。所以這個測試結果是無效的。
有人說,這個例子太弱了,結果集差了100倍,性能當然不一樣了。那是不是數據總量和結果集大小都一致,測試結果就是有效了呢?
案例2. 查詢本院一個月內收的案件,相應SQL如下:
select * from T_AJ
where N_FY=10 and D_LARQ between '20110101' and '20110201'
這個操作,查出來的結果只有一千條數據,屬于正常范圍。但查詢的時間還是超過5秒,依然超出了我們的預期。
在正常數據中,每家法院的數據可能占總數據量的1%,一個月時間段內的數據可能占總數據量更少,假設是0.5%。那么這時我們通過N_FY和 D_LARQ兩個條件進行查詢,數據庫會進行估算:符合D_LARQ查詢條件的數據大概有5000條,符合N_FY查詢條件的數據大概有1萬條,那么用 D_LARQ上的索引進行查詢是最快的,可以迅速的將查詢范圍縮小到5000條,然后在這5000條中去檢查N_FY是否也符合條件。
過程如圖一所示(手繪草圖^_^)。
圖一
注:數據按行存儲,小方塊表示符合該列查詢條件的數據,陰影表示符合所有查詢條件,也就是最終的結果集。箭頭線段表示為了完成查詢,需要掃描的數據量,本圖中即符合LARQ查詢條件的數據。下同。
但在本例中不正常的數據條件下,數據庫會知道:符合N_FY查詢條件的數據有50萬條,符合D_LARQ的也有近50萬條,如果使用其中一列的 索引將一百萬的范圍縮減到50萬,比從頭到尾掃描整個表做的工作還要多(為什么呢?需要了解索引的結構和原理),那還是不要用索引了吧。于是數據庫會依次 檢查每一條數據,判斷N_FY和D_LARQ是否符合條件。
如圖二所示。
圖二
注:本圖中實際掃描的數據量就是整張表的數據,但結果集和圖一是一樣大的。
這樣,就可以知道,總數據量一樣,結果集大小一樣,為什么性能差了很多了。就是因為數據分布不合理,導致數據庫無法正常使用索引,從而進行了全 表掃描。當然,這個數據分布,我們依然可以歸類到結果集中去,那就是要保證每一個查詢條件“單獨的結果集”都要符合真實情況,而不僅僅是整個查詢最終的 “總結果集”。
看個這兩個簡單的小例子,我們再來總結一下關于測試數據,需要注意的內容:
-
最根本、也是大家都知道的就是數據量,性能測試必須保證能在預期的數據量下進行測試。在一萬條記錄中查詢,和在一百萬數據中查詢,顯然是大大不同的,可以把數據量看做一種“壓力”,這個就不用再解釋了。
但是在比較大型的系統中,這一點可能也不是很容易做好,因為這類系統往往有著復雜的數據庫,上百張的數據表。對每張表都進行數據模擬顯然是不現實 的,也是沒有意義的,因為不是每張表都涉及到大數據量。那么如何選取不容易遺漏呢?通常通過兩種方式:從設計和業務角度分析表間關系、從現有實際數據量進 行分析推測。
-
確保結果集在正常范圍內。結果集的大小直接影響后續很多工作的性能,如數據排序分組、分頁、程序中的邏輯校驗或者是展現。
-
數據分布必須合理,盡量接近真實。數據的分布,其實也就是數據的真實性,它直接決定了數據庫是否使用索引、選用哪個索引,也就是常說的查詢計劃。不同的查詢計劃也就是不同的數據訪問路徑,性能差別可能會很大。
這里主要涉及到的是索引的問題,需要大家對索引的原理有一定的了解,索引如何工作、數據庫如何選擇索引、和索引有關的一寫重要概念如區分度(selectivity)等等。
- 最好的數據來自生產環境。這是顯而易見的,使用真實的數據測出來的結果才是最準確的。但是絕大多數情況下,我 們沒有這樣的好運,可能是客戶禁止、也可能是生產環境數據量比較小。那就只好自己想辦法來模擬了,需要注意的也就是上面說到的幾點。這里再推薦一種方法, 數據翻倍。比如已經有了真實的數據十萬條,但我們需要一百萬條,那就可以通過寫一些SQL或者存儲過程,將現有的數據不斷翻倍(簡單的說,復制到臨時表, 根據需要修改一些列,再插回到原表),這樣的數據真實性還是比較高的。
關于測試數據,我想說的就是以上幾點了。另外再補充上一些相關內容,也是性能測試人員需要關注的。
-
重點了解IO的概念,更準確的說應該是物理IO。一般來講,數據庫的瓶頸或者查詢的主要耗時就是IO。所以,數據庫優化的一個重要方向就是盡量減小IO。
IO是不是只和數據量(行數)有關呢?舉一個例子:
select co1, col2, col3, col4, col5 from T_AJ
where condition...T_AJ數據量有100萬,表中有近200列,此查詢耗時大于10秒。而另一種實現方式,首先將col1-col5以及查詢條件中的幾個列的數據抽取到一張臨時表(#T_AJ)中。然后,
select co1, col2, col3, col4, col5
from #T_AJ where condition...臨時表#T_AJ和原數據表有同樣的數據量(行數),但是此查詢卻只需要1秒(暫不考慮抽取到臨時表的耗時),這就是不同IO引起的差異。通常我們 使用的數據庫都是行式存儲的,可以簡單的理解為,一行數據從頭讀到尾,才能進入到下一行。這樣,不管一行中的200列,你只讀取其中的一列還是幾列,其余 的190多列仍然需要一定的IO。在大數據量下,這個性能差異就很明顯了。所以上面的這個例子就是一種典型的優化手段,索引覆蓋也是處理類似問題的典型方 法,各位自行了解吧。列式存儲數據庫(如Sybase IQ)之所以性能這么高,也是同樣的道理。
-
盡量深入了解這些概念,如執行計劃,基于開銷的估算,統計信息等等。我用一句話來簡單描述:數據庫通過統計信息來估計查詢開銷,統計信息不準時,開銷估計就可能不準確,從而導致選擇了錯誤的執行計劃。
-
測試過程中數據的清理。性能測試過程中可能又會生成大量的數據,積累到一定程度又會對性能結果造成影響,所以每一輪測試時都應該清理掉之前測試過程中產生的數據,保證每次測試是在相同的條件下進行的。
-
性能測試過程中,如果定位到了某一個查詢或SQL有問題,首先要確認的是數據是否合理。通過查詢計劃來判斷是否按預期進行了查詢,如果不是,查看數據的分布是否真實。一般數據庫會提供很多種手段來進行驗證。
posted on 2012-05-21 12:04 順其自然EVO 閱讀(285) 評論(0) 編輯 收藏 所屬分類: loadrunner 、性能測試