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