asp.net下數(shù)據(jù)庫(kù)操作優(yōu)化一例
更新時(shí)間:2010年11月19日 16:24:08 作者:
數(shù)據(jù)庫(kù)升級(jí),需要對(duì)幾個(gè)表進(jìn)行一些數(shù)據(jù)轉(zhuǎn)換,具體是這樣:針對(duì)每一個(gè) Item,從 orders 表里查出 Shop_Id,并把此 Id 賦值給 items 和 skus 中的 Shop_Id。
下面是最初實(shí)現(xiàn)的代碼,其中 LargerResultProcessor 是一個(gè)基類,負(fù)責(zé)遍歷泛型參數(shù) T 所指向的數(shù)據(jù)庫(kù)表,并以每頁(yè) 100 項(xiàng)的方式分頁(yè),并對(duì)每一項(xiàng)調(diào)用 ProcessItem 函數(shù),而子類只需實(shí)現(xiàn) ProcessItem 函數(shù)即可:
public class ItemRenameCompanyId : LargerResultProcessor<Item>
{
protected override void ProcessItem(Item item)
{
const string template1 = @"select top 1 shop_id from orders where Item_id = '{0}'";
var sql1 = string.Format(template1, item.Id);
const string template2 = @"update Items set shop_id={0} where id = {1};
update skus set shop_id={0} where item_id = {1};";
try
{
var obj = DbEntry.Context.ExecuteScalar(sql1);
var sql2 = string.Format(template2, long.Parse(obj.ToString()), item.Id);
DbEntry.Context.ExecuteNonQuery(sql2);
}
catch (Exception exception)
{
Logger.Default.Warn(exception + item.Id.ToString());
}
}
}
上面這段代碼,邏輯比較簡(jiǎn)單,針對(duì)每一項(xiàng),使用 Select 語(yǔ)句取出 Shop_Id,并且執(zhí)行 Update,只是有個(gè)問題,就是執(zhí)行速度比較慢,對(duì)于我們 6 萬(wàn)左右 Item,4 萬(wàn)左右 Sku,99 萬(wàn)左右 Order 的表,需要執(zhí)行約 40 分鐘,才能轉(zhuǎn)換完畢。
這些代碼,雖然是一次性操作,但是對(duì)于運(yùn)行系統(tǒng),停機(jī)時(shí)間越短越好,于是進(jìn)行一些優(yōu)化工作,數(shù)據(jù)庫(kù)對(duì)于大量重復(fù)的語(yǔ)句,如果使用參數(shù)的方式,因?yàn)榭梢员苊鈱?duì)于語(yǔ)句的重復(fù)解析工作,所以速度會(huì)快一些,按照這個(gè)思路,簡(jiǎn)單的修改如下:
public class ItemRenameCompanyId : LargerResultProcessor<Item>
{
protected override void ProcessItem(Item item)
{
const string template1 = @"select top 1 shop_id from orders where Item_id = @id";
const string template2 =
@"update Items set shop_id=@sid where id = @id;
update skus set shop_id=@sid where item_id = @id;";
try
{
var sql1 = new SqlStatement(template1, new DataParameter("@id", item.Id));
var sid = Convert.ToInt64(DbEntry.Context.ExecuteScalar(sql1));
var sql2 = new SqlStatement(template2, new DataParameter("@sid", sid), new DataParameter("@id", item.Id));
DbEntry.Context.ExecuteNonQuery(sql2);
}
catch (Exception exception)
{
Logger.Default.Warn(exception + item.Id.ToString());
}
}
}
測(cè)試這個(gè)程序,大概 25 分鐘可以完成轉(zhuǎn)換。有一些提高,不過,我們真正要修改的數(shù)據(jù)量并不大,一共只有 6 萬(wàn) 加 4 萬(wàn) 大約 10 萬(wàn)條數(shù)據(jù),所以 25 分鐘還是有些長(zhǎng)了。簡(jiǎn)單分析后,Orders 是最大的表,如果整體速度慢,則導(dǎo)致速度慢最大的可能因素,應(yīng)該是查詢 Orders,所以稍換一個(gè)思路,提前把 Item_Id 和 Shop_Id 的對(duì)應(yīng)關(guān)系查找出來(lái),放到內(nèi)存里,從而避免每次 ProcessItem 都要進(jìn)行 Orders 表的查詢。至于內(nèi)存里的數(shù)據(jù),本來(lái)準(zhǔn)備用 Dictionary 的,后來(lái)一想,Id 都是 long 型的數(shù)據(jù),而且不能算“稀疏”矩陣,基本可以稱為“稠密”矩陣,所以,直接用數(shù)組應(yīng)該是速度更快,所以先查詢出 Items 的最大 Id,用于設(shè)置數(shù)組大小,再按索引賦值即可:
public class ItemRenameCompanyId : LargerResultProcessor<Item>
{
private readonly long[] _dic;
public ItemRenameCompanyId()
{
var count = Convert.ToInt64(DbEntry.Context.ExecuteScalar("select top 1 Id from items order by id desc")) + 10;
_dic = new long[count];
var sql =
new SqlStatement(
"select items.id as xiid,orders.shop_id as xsid from items inner join orders on orders.item_id = items.id group by items.id,orders.shop_id")
{SqlTimeOut = 300};
dynamic list = DbEntry.Context.ExecuteDynamicList(sql);
foreach(dynamic row in list)
{
_dic[row.xiid] = row.xsid;
}
}
protected override void ProcessItem(Item item)
{
const string template2 =
@"update Items set shop_id=@sid where id = @id;
update skus set shop_id=@sid where item_id = @id;";
try
{
var sid = _dic[item.Id];
var sql2 = new SqlStatement(template2, new DataParameter("@sid", sid), new DataParameter("@id", item.Id));
DbEntry.Context.ExecuteNonQuery(sql2);
}
catch (Exception exception)
{
Logger.Default.Warn(exception + item.Id.ToString());
}
}
}
再測(cè)試這一段程序,運(yùn)行 70 秒就完成了數(shù)據(jù)轉(zhuǎn)換,另外,查詢對(duì)應(yīng)關(guān)系那一句 SQL,因?yàn)獒槍?duì)的是剛恢復(fù)的數(shù)據(jù)庫(kù),所以用了大概 3、40 秒,實(shí)際使用查詢管理器,在運(yùn)行中的數(shù)據(jù)庫(kù)執(zhí)行那一句 SQL,只需要 1 秒左右就可以完成,所以,估計(jì)在實(shí)際轉(zhuǎn)換的時(shí)候,3、40 秒就可以完成轉(zhuǎn)換了。
復(fù)制代碼 代碼如下:
public class ItemRenameCompanyId : LargerResultProcessor<Item>
{
protected override void ProcessItem(Item item)
{
const string template1 = @"select top 1 shop_id from orders where Item_id = '{0}'";
var sql1 = string.Format(template1, item.Id);
const string template2 = @"update Items set shop_id={0} where id = {1};
update skus set shop_id={0} where item_id = {1};";
try
{
var obj = DbEntry.Context.ExecuteScalar(sql1);
var sql2 = string.Format(template2, long.Parse(obj.ToString()), item.Id);
DbEntry.Context.ExecuteNonQuery(sql2);
}
catch (Exception exception)
{
Logger.Default.Warn(exception + item.Id.ToString());
}
}
}
上面這段代碼,邏輯比較簡(jiǎn)單,針對(duì)每一項(xiàng),使用 Select 語(yǔ)句取出 Shop_Id,并且執(zhí)行 Update,只是有個(gè)問題,就是執(zhí)行速度比較慢,對(duì)于我們 6 萬(wàn)左右 Item,4 萬(wàn)左右 Sku,99 萬(wàn)左右 Order 的表,需要執(zhí)行約 40 分鐘,才能轉(zhuǎn)換完畢。
這些代碼,雖然是一次性操作,但是對(duì)于運(yùn)行系統(tǒng),停機(jī)時(shí)間越短越好,于是進(jìn)行一些優(yōu)化工作,數(shù)據(jù)庫(kù)對(duì)于大量重復(fù)的語(yǔ)句,如果使用參數(shù)的方式,因?yàn)榭梢员苊鈱?duì)于語(yǔ)句的重復(fù)解析工作,所以速度會(huì)快一些,按照這個(gè)思路,簡(jiǎn)單的修改如下:
復(fù)制代碼 代碼如下:
public class ItemRenameCompanyId : LargerResultProcessor<Item>
{
protected override void ProcessItem(Item item)
{
const string template1 = @"select top 1 shop_id from orders where Item_id = @id";
const string template2 =
@"update Items set shop_id=@sid where id = @id;
update skus set shop_id=@sid where item_id = @id;";
try
{
var sql1 = new SqlStatement(template1, new DataParameter("@id", item.Id));
var sid = Convert.ToInt64(DbEntry.Context.ExecuteScalar(sql1));
var sql2 = new SqlStatement(template2, new DataParameter("@sid", sid), new DataParameter("@id", item.Id));
DbEntry.Context.ExecuteNonQuery(sql2);
}
catch (Exception exception)
{
Logger.Default.Warn(exception + item.Id.ToString());
}
}
}
測(cè)試這個(gè)程序,大概 25 分鐘可以完成轉(zhuǎn)換。有一些提高,不過,我們真正要修改的數(shù)據(jù)量并不大,一共只有 6 萬(wàn) 加 4 萬(wàn) 大約 10 萬(wàn)條數(shù)據(jù),所以 25 分鐘還是有些長(zhǎng)了。簡(jiǎn)單分析后,Orders 是最大的表,如果整體速度慢,則導(dǎo)致速度慢最大的可能因素,應(yīng)該是查詢 Orders,所以稍換一個(gè)思路,提前把 Item_Id 和 Shop_Id 的對(duì)應(yīng)關(guān)系查找出來(lái),放到內(nèi)存里,從而避免每次 ProcessItem 都要進(jìn)行 Orders 表的查詢。至于內(nèi)存里的數(shù)據(jù),本來(lái)準(zhǔn)備用 Dictionary 的,后來(lái)一想,Id 都是 long 型的數(shù)據(jù),而且不能算“稀疏”矩陣,基本可以稱為“稠密”矩陣,所以,直接用數(shù)組應(yīng)該是速度更快,所以先查詢出 Items 的最大 Id,用于設(shè)置數(shù)組大小,再按索引賦值即可:
復(fù)制代碼 代碼如下:
public class ItemRenameCompanyId : LargerResultProcessor<Item>
{
private readonly long[] _dic;
public ItemRenameCompanyId()
{
var count = Convert.ToInt64(DbEntry.Context.ExecuteScalar("select top 1 Id from items order by id desc")) + 10;
_dic = new long[count];
var sql =
new SqlStatement(
"select items.id as xiid,orders.shop_id as xsid from items inner join orders on orders.item_id = items.id group by items.id,orders.shop_id")
{SqlTimeOut = 300};
dynamic list = DbEntry.Context.ExecuteDynamicList(sql);
foreach(dynamic row in list)
{
_dic[row.xiid] = row.xsid;
}
}
protected override void ProcessItem(Item item)
{
const string template2 =
@"update Items set shop_id=@sid where id = @id;
update skus set shop_id=@sid where item_id = @id;";
try
{
var sid = _dic[item.Id];
var sql2 = new SqlStatement(template2, new DataParameter("@sid", sid), new DataParameter("@id", item.Id));
DbEntry.Context.ExecuteNonQuery(sql2);
}
catch (Exception exception)
{
Logger.Default.Warn(exception + item.Id.ToString());
}
}
}
再測(cè)試這一段程序,運(yùn)行 70 秒就完成了數(shù)據(jù)轉(zhuǎn)換,另外,查詢對(duì)應(yīng)關(guān)系那一句 SQL,因?yàn)獒槍?duì)的是剛恢復(fù)的數(shù)據(jù)庫(kù),所以用了大概 3、40 秒,實(shí)際使用查詢管理器,在運(yùn)行中的數(shù)據(jù)庫(kù)執(zhí)行那一句 SQL,只需要 1 秒左右就可以完成,所以,估計(jì)在實(shí)際轉(zhuǎn)換的時(shí)候,3、40 秒就可以完成轉(zhuǎn)換了。
您可能感興趣的文章:
- 對(duì)于ASP編碼問題的深入研究與最終解決方案
- Asp.Net 網(wǎng)站優(yōu)化系列之?dāng)?shù)據(jù)庫(kù)優(yōu)化分字訣上 分庫(kù)
- Asp.Net 網(wǎng)站優(yōu)化系列之?dāng)?shù)據(jù)庫(kù)優(yōu)化 分字訣 分表(縱向拆分,橫向分區(qū))
- Asp.Net 網(wǎng)站優(yōu)化系列之?dāng)?shù)據(jù)庫(kù)優(yōu)化措施 使用主從庫(kù)(全)
- asp.net小談網(wǎng)站性能優(yōu)化
- Asp.net 網(wǎng)站性能優(yōu)化二則分享
- ASP.NET性能優(yōu)化之讓瀏覽器緩存動(dòng)態(tài)網(wǎng)頁(yè)的方法
- ASP.NET性能優(yōu)化之減少請(qǐng)求
- asp.net程序優(yōu)化 盡量減少數(shù)據(jù)庫(kù)連接操作
- Asp.Net性能優(yōu)化技巧匯總
- Asp編碼優(yōu)化技巧
相關(guān)文章
asp.net實(shí)現(xiàn)遞歸方法取出菜單并顯示在DropDownList中(分欄形式)
這篇文章主要介紹了asp.net實(shí)現(xiàn)遞歸方法取出菜單并顯示在DropDownList中的方法,涉及asp.net遞歸算法與DropDownList使用技巧,需要的朋友可以參考下2016-06-06
WPF使用VisualTreeHelper進(jìn)行命中測(cè)試
這篇文章介紹了WPF使用VisualTreeHelper進(jìn)行命中測(cè)試的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
ASP.NET?MVC5網(wǎng)站開發(fā)之用戶添加和瀏覽2(七)
這篇文章主要為大家詳細(xì)介紹了ASP.NET?MVC5網(wǎng)站開發(fā)之用戶添加和瀏覽,感興趣的小伙伴們可以參考一下2016-08-08
ASP.NET2.0中用Gridview控件操作數(shù)據(jù)的代碼
在ASP.NET 2.0中,加入了許多新的功能和控件,相比asp.net 1.0/1.1,在各方面都有了很大的提高2012-10-10
一步步打造簡(jiǎn)單的MVC電商網(wǎng)站BooksStore(1)
這篇文章主要和大家一起一步步打造一個(gè)簡(jiǎn)單的MVC電商網(wǎng)站,MVC電商網(wǎng)站BooksStore第一篇,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04
.Net Core下HTTP請(qǐng)求IHttpClientFactory示例詳解
這篇文章主要給大家介紹了關(guān)于.Net Core下HTTP請(qǐng)求IHttpClientFactory的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用.Net Core具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
在.NET中掃描局域網(wǎng)服務(wù)的實(shí)現(xiàn)方法
下面小編就為大家分享一篇在.NET中掃描局域網(wǎng)服務(wù)的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-01-01

