其實性能測試我前面已經(jīng)提到了很多,為什么還要把數(shù)據(jù)庫單拿出來說呢?
因為數(shù)據(jù)庫服務(wù)器本身與其他的一些普通的APP服務(wù)器是很不一樣的。 之前我接觸過很多項目,都是因為數(shù)據(jù)庫的原因?qū)е铝撕芏嘈阅軉栴},比如死鎖,索引等等
關(guān)于內(nèi)存
我們在進(jìn)行服務(wù)器的內(nèi)存的測試的時候,如果是普通的APP server,當(dāng)我們對內(nèi)存進(jìn)行監(jiān)控時,通常都是有一個metrics, 比如某個APP的service的內(nèi)存使用量不能超過總量的百分之多少,對于整個sever來說,通常也會有比較多的內(nèi)存剩余。
而當(dāng)我們?nèi)ゲ榭匆粋€數(shù)據(jù)庫server的時候,會發(fā)現(xiàn)可用的內(nèi)存量通常只有10M或者5M(取決于你的配置)...... 而當(dāng)你把你的數(shù)據(jù)庫的內(nèi)存增加一倍,可用的內(nèi)存通常還是只有10M左右,這是什么原因呢?
其實這于數(shù)據(jù)庫本身的工作原理有關(guān)系,數(shù)據(jù)庫中io操作的基本單位為頁,當(dāng)數(shù)據(jù)庫執(zhí)行一條語句,比如一條查詢語句,他會先從物理磁盤中把相應(yīng)的頁加載到內(nèi)存,然后在進(jìn)行操作。
因為數(shù)據(jù)庫本身就不停的讀寫的過程,所以數(shù)據(jù)庫中內(nèi)存當(dāng)中會緩存各種各樣的數(shù)據(jù),為了更快的讀寫速度,數(shù)據(jù)庫會有算法去維護(hù)這些內(nèi)存中的數(shù)據(jù),以保證盡可能的使得數(shù)據(jù)都是從內(nèi)存中獲得,而不是從物理內(nèi)存中得到(內(nèi)存的訪問速度是納秒級,硬盤是微秒級)。所以一般來說,數(shù)據(jù)庫會基本用光所有的內(nèi)存。
這就是為什么數(shù)據(jù)庫會吃內(nèi)存了,這與他的工作原理有關(guān)系,只要能保證系統(tǒng)能正常運(yùn)行就可以了,其他的內(nèi)存都可以用來緩存數(shù)據(jù)。
關(guān)于死鎖
死鎖通常是指爭搶資源不當(dāng),讓雙方因為對方掌握了自己的資源而無限期的等下去。如下圖所示:

發(fā)生死鎖的原因很多,大部分是由于事務(wù)之間對資源訪問順序的交替,或者并發(fā)修改統(tǒng)一記錄導(dǎo)致的,數(shù)據(jù)庫對待死鎖有著不同的策略,對于SQL server來說,它會隨機(jī)殺掉其中的一個,至少保證另外一個事務(wù)的正常運(yùn)行;而對于Oracle來說,它會對兩個事務(wù)進(jìn)行一個評估,會殺掉它認(rèn)為不那么重要的一個。
所以我們在數(shù)據(jù)層面,需要去監(jiān)控死鎖的發(fā)生情況,一般來說,死鎖是不可避免的,但是一旦死鎖發(fā)生頻率很多,必定會影響到業(yè)務(wù)。
我們可以用很多工具去監(jiān)控死鎖,比如SQL Profile。對于死鎖的修正也是對于高并發(fā)的事務(wù),盡量減少長度;把鎖的優(yōu)先級調(diào)整低一些(用低隔離級別);按同一順序訪問對象,盡量避免事務(wù)中的用戶交互。
關(guān)于磁盤
因為對于數(shù)據(jù)庫來說,最重要的就是讀寫的操作,磁盤對于數(shù)據(jù)庫來說是非常重要的。
現(xiàn)在好多數(shù)據(jù)庫都是直接放在云盤上的,云盤上的磁盤有這自己的結(jié)構(gòu),但是很多年前,如果是自己的服務(wù)器,我們還要考慮到磁盤陣列,來保證磁盤的效率和安全性。
對于磁盤來說,我們通常會從讀寫方面來衡量,有幾個比較通過的指標(biāo)可以用來衡量數(shù)據(jù)庫磁盤的性能,比如Average Disk queue lenth,數(shù)據(jù)生命周期等等。
另外值得一提的是數(shù)據(jù)庫的碎片整理。當(dāng)數(shù)據(jù)庫讀寫一段時間之后,由于頻繁的插入數(shù)據(jù),會導(dǎo)致數(shù)據(jù)并不是按照順序排列在磁盤上面,這樣當(dāng)我們在查相關(guān)的數(shù)據(jù)的時候,磁盤往往要去不同的區(qū)域查找數(shù)據(jù),導(dǎo)致性能降低,這個時候我們很有必要去運(yùn)行磁盤的碎片整理的一些job,來保證我們的數(shù)據(jù)庫性能。
但是這個job本身就很占磁盤的i/O,所以盡量選擇系統(tǒng)不忙的時候進(jìn)行。
關(guān)于索引
我相信索引是大家很熟悉的一個話題了,當(dāng)數(shù)據(jù)量很小時,不建索引,進(jìn)行全表掃描的的性能尚可接受。但是數(shù)據(jù)量大時,必須借助索引。所以索引的適當(dāng)與否,是性能還壞的關(guān)鍵。
比如執(zhí)行一條語句
SELECT UserName, UserID? FROM US.UserDetail WHERE UserName = “李四”
這條語句這樣執(zhí)行過程與創(chuàng)建的索引有關(guān)系,如果沒有索引就需要進(jìn)行全表掃描,這樣加載到內(nèi)存當(dāng)中的頁在數(shù)據(jù)量很大的情況下就相當(dāng)多了。如果建立了適當(dāng)?shù)乃饕?,可能只需要加載幾頁內(nèi)存就可以了。
當(dāng)我們用一些工具比如sql profile跟蹤到一些長的查詢的時候,我們就需要去看看索引是否建立恰當(dāng)。這在數(shù)據(jù)庫的優(yōu)化中也是很重要的一個方面。當(dāng)然,索引雖然對讀的性能有幫助,但是對寫的性能卻有影響。
我們也需要再適當(dāng)?shù)臅r候reindex索引,原因就是如果索引在物理存儲上不連續(xù),也會導(dǎo)致性能的下降,這與磁盤的碎片整理是一個道理。
一般來說,如果系統(tǒng)設(shè)計合理,最終的瓶頸都會出現(xiàn)在數(shù)據(jù)庫上,而我們在做性能測試時,也需要了解數(shù)據(jù)庫的特殊之處,去更好的做性能測試