首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

.NET 應用程式資料庫存取效能優化:避免 N+1 查詢與善用記憶體組裝

     編輯:關於.NET

前言:一個真實的效能災難現場

專案需求:從資料庫讀取全國行政區域資料 (省/市/區三層),提供給前端下拉選單。資料表結構簡單:

District 資料表結構

使用代碼生成器 (動軟 .NET 代碼生成器 + CodePlex Stored Procedure Generator) 產生三層架構基礎代碼。

初版實作:經典 N+1 查詢反模式

List<District> topDistrictList = new List<District>();
DistrictBLL dictrictBll = new DistrictBLL();

// 1. 查詢頂層 (父代碼 = 0)
topDistrictList = dictrictBll.GetEntityList(
    string.Format("DisFatherCode='{0}' {1}", 0, Settings.District_Order_By));

// 2. 迴圈每個頂層,再查一次子節點 → N+1 次資料庫往返
foreach (District dis in topDistrictList)
{
    dis.ChildrenDis = dictrictBll.GetEntityList(
        string.Format("DisFatherCode='{0}' {1}", dis.DisCode, Settings.District_Order_By));
}
return topDistrictList;

結果:兩層資料耗時 ~5 秒 勉強可接受;三層資料飆升至 50 秒 完全無法上線。

HttpWatch 分析網路時間

優化策略:一次撈全量,記憶體中組裝樹狀結構

List<District> districtList = new List<District>();
DistrictBLL dictrictBll = new DistrictBLL();

// 1. 單次查詢撈取頂層 + 次層所有資料 (WHERE 條件合併)
districtList = dictrictBll.GetEntityList(
    string.Format(" {0} {1}", Settings.Get_Top_And_Second_District_Where, Settings.District_Order_By));

// 2. LINQ 記憶體分組組裝父子關係
var top = from c in districtList
          where c.DisFatherCode.Trim() == "0"
          select c;

var second = from c in districtList
             where c.DisFatherCode.Trim() != "0"
             select c;

foreach (District dis in top)
{
    var se = from c in second
             where c.DisFatherCode == dis.DisCode
             select c;
    dis.ChildrenDis = se.ToList<District>();
}
return top.ToList<District>();

效能躍升:

  • 兩層資料:5 秒 → 0.5 秒 (10x)
  • 三層資料:50 秒 → 2 秒 (25x)

核心心法總結

「不要多次往返資料庫」 — 每次連線/查詢/關閉都有固定開銷 (Connection Pooling 也無法消除網路往返與協定解析成本)。
「一次撈足量資料,C# 記憶體中組裝」 — 現代伺服器記憶體充裕,LINQ/PLINQ 處理物件圖極快,資料庫只負責「過濾與投影」。

延伸思考:取多少才算「足量」?

  • 小型主檔 (行政區、字典表) → 全表撈入記憶體快取
  • 大型交易表 → 分頁 + 索引 + 僅撈必要欄位
  • 關鍵原則:以業務需求為邊界,而非技術慣性

後續主題預告

下一篇將探討 快取策略:

  • HttpRuntime.Cache / MemoryCache 進階用法
  • 檔案相依性快取 (CacheDependency)
  • SQL 資料庫相依性快取 (SqlCacheDependency)
  • 分散式快取 (Redis / NCache / AppFabric) 選型指南

工具推薦

  • 動軟 .NET 代碼生成器 — 三層架構全自動產生
  • Stored Procedure Generator (CodePlex) — SP 批量產出
  • HttpWatch — 瀏覽器端網路時間線分析 (IE/FF)
  • LINQ 體驗系列教學 — 掌握記憶體查詢與組裝技巧
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved