利用Cache緩存數(shù)據(jù)DataTable數(shù)據(jù)提高大數(shù)據(jù)量訪問性能
2024-07-21 02:23:53
供稿:網(wǎng)友
引言:
在數(shù)據(jù)量不大的情況下,程序怎么寫基本上性能差別不大,但是當(dāng)我們面對數(shù)以萬計(jì)的數(shù)據(jù)的時候,我想性能就是個不得不考慮的問題了,每寫一個方法,每填充一筆數(shù)據(jù)都要考慮到性能問題,否則服務(wù)器將承擔(dān)巨大的執(zhí)行開銷,如果服務(wù)器性能不好可能立即就死在那里了,所以在大數(shù)據(jù)量頻繁訪問的頁面上,我們就必須考慮如何提高頁面的性能了,本文將提供一種用cache提高訪問性能的方法來解決此問題,在很大程度上提高頁面加載數(shù)據(jù)的性能。本文列舉的是論壇版塊中帖子列表頁面加載數(shù)據(jù)的實(shí)例。
正文:
每個版塊帖子列表信息都會對應(yīng)一個cache的名字,比如,我們可以按照規(guī)律設(shè)成
#region -- cachename setting --
boardcachename = "board" + boardid.tostring();
#endregion
這里我們同樣是采取數(shù)據(jù)集填充datatable的方法創(chuàng)建數(shù)據(jù)的。不過,因?yàn)槲覀冇辛薱ache,所以,我們在第一次加載完數(shù)據(jù)后,會把數(shù)據(jù)壓到cache中,然后每次填充datatable前進(jìn)行判斷,如果cache為空時才加載,如果不為空,則不加載。
private datatable builddatatable()
{
// 數(shù)據(jù)緩存 機(jī)制
if(cache[boardcachename] != null)
{
// create datatable from cache
datatable dt = (datatable)cache[boardcachename];
return dt;
}
else
{
// create datatable from database
datatable dt = new datatable();
#region -- create datatable --
dt.columns.add("topicid", system.type.gettype("system.int32"));
//省去n個類似字段的添加
dt.columns.add("coolstate", system.type.gettype("system.int32"));
datacolumn[] keys = new datacolumn[1];
keys[0] = dt.columns[0];
dt.primarykey = keys;
#endregion
#region -- add datarow --
bbstopiccollection btc = new bbstopiccollection();
btc.boardid = this.boardid;
btc.topicstate = 1;
if(!btc.getinfo())
{
return dt;
}
for(int i=0;i<btc.count;i++)
{
datarow dr = dt.newrow();
// 帖id
dr["topicid"] = btc[i].id;
//省去n個類似字段的數(shù)據(jù)賦值
// cool state
dr["coolstate"] = btc[i].coolstate;
dt.rows.add(dr);
}
#endregion
// push datatable to cache
cache[boardcachename] = dt;
return dt;
}
}
上面的代碼完成了數(shù)據(jù)填充過程,但更重要的是對數(shù)據(jù)進(jìn)行管理,比如,我們改變一條住處的某些狀態(tài)位來實(shí)現(xiàn)一些功能,比如,我們把貼子加成“酷貼”,這個時候就要對cache進(jìn)行操作,特別注意一下,我們在上面的代碼中還特別設(shè)置topicid這一列作為表的主值鍵,這樣我們才能很快的定位到要管理的數(shù)據(jù)信息,方法如下。
#region -- cache management --
if(cache["board" + this.boardid.tostring()] != null)
{
datatable dt = (datatable)cache["board" + this.boardid.tostring()];
datarow dr = dt.rows.find(topicid);
if(dr != null)
{
dr["coolstate"] = 1;
dr.acceptchanges();
dt.acceptchanges();
}
}
#endregion
一點(diǎn)說明:其中的topicid是通過某種途徑傳過來的你想操作的信息的唯一標(biāo)識字段,acceptchanges方法更新保存相應(yīng)對象數(shù)據(jù)自上一次更新以來所有的更改,另外對cache進(jìn)行操作后,記得要重新綁定數(shù)據(jù),另外也要同時更新數(shù)據(jù)庫中的,本文認(rèn)為讀者具備對數(shù)據(jù)庫數(shù)據(jù)進(jìn)行操作的能力,便不作贅述。
那么我們?nèi)绾蝸韯h除數(shù)據(jù)記錄呢?我們是不是可以直接在找到dr的那一行下面,用個
dr.delete()來把數(shù)據(jù)刪除就完事了呢?答案是否,這樣操作會出現(xiàn)問題,經(jīng)測試對cache的添加和更新操作會立即生效,但刪除某條記錄的動作不會立即起作用,這樣就會導(dǎo)致數(shù)據(jù)操作異步性,這是不可以的,同時1.1版本比1.0版本要稍微好一些,但還是解決不了異步性的問題,所以我們是不是必須把cache干掉,重新填充一下呢,如果你愿意這樣做,自然也無可厚非,我這里提供另外一個思路供參考。
我們的解決方案是,在創(chuàng)建表格的時候多加一個刪除標(biāo)志位,比如deletestate,當(dāng)初從數(shù)據(jù)庫中加載出來的時候都一律為1,然后經(jīng)過刪除操作以后,將這條信息的刪除標(biāo)志位置0(不要忘記同時操作數(shù)據(jù)庫中的數(shù)據(jù)),然后綁定的時候?qū)ataview進(jìn)行過濾,dv.rowfilter = "deletestate==1",便可以模擬出刪除效果了。
數(shù)據(jù)經(jīng)過這樣的處理之后,訪問性能會數(shù)以百倍的提高,數(shù)據(jù)只在cache失效后才會重新加載,用戶對數(shù)據(jù)的訪問都是對cache的操作,而且cache是服務(wù)器變量,對所有用戶共享,這樣,如果同時有一百個用戶訪問,也都是對同一個cache進(jìn)行一百次訪問,而程序訪問cache是非常快的,如果不使用cache,那么,我們就要去跑一百次數(shù)據(jù)庫操作,性能極差,尤其是當(dāng)海量用戶對海量數(shù)據(jù)進(jìn)行訪問的時候,服務(wù)器可謂苦不堪言,所以用cache來緩解負(fù)荷是相當(dāng)必要且相對優(yōu)良的一種方案,只是辛苦了那位在cache失效后第一次訪問頁面的那個用戶,不過這種犧牲換來別人的高性能也是值得的嘛。