首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

DB2 Web 應用效能優化五大鐵律:從 C# 實戰看數據庫訪問模式的生死抉擇

     編輯:MySQL 資料庫相關知識

前言:優化的本質是習慣而非規則

原文以 Borland C#Builder + DB2 UDB 8.1 + ASP.NET 為例,但五大鐵律**普適於所有關係型數據庫與應用框架組合**。核心思想:將數據庫視為稀缺資源,以最小代價獲取業務所需數據。

鐵律一:按需檢索 — 禁止 SELECT *

實測對比 (10,000 行 × 10 欄表)

延伸:WHERE 子句限制行數

-- 差:應用層過濾
DataTable dt = GetAllUsers(); // 100萬行
var vip = dt.AsEnumerable().Where(r => r.Field("Level") > 5);

// 優:資料庫層過濾
SELECT UserID, Name, Email FROM Users WHERE Level > 5; -- 命中索引,返回 500 行

原則:越早過濾 (資料庫 > 網絡 > 應用層),總體代價越低。

鐵律二:優化數據庫 — 索引是銀彈,統計是彈藥

索引建立決策樹

WHERE/JOIN/ORDER BY/GROUP BY 涉及欄位?
├─ 基數高 (唯一值多) → B-Tree 索引 (單欄/組合)
├─ 基數低 (性別/狀態) → 不建索引,或組合索引前綴
├─ 全文搜尋 → Fulltext Index / ngram
├─ 空間查詢 → Spatial Index
└─ JSON 欄位 → Functional Index / Generated Column + Index

DB2 專用工具:Index Advisor (索引建議器)

-- 提交工作負載 SQL 集合
db2advis -d sample -s "SELECT * FROM orders WHERE cust_id=100 AND order_date>'2024-01-01'" -o advice.txt

-- 輸出建議
CREATE INDEX IDX_ORDERS_CUST_DATE ON ORDERS (CUST_ID, ORDER_DATE);
-- Estimated improvement: 95%

通用做法:定期收集慢查詢、EXPLAIN 輸出,餵給索引建議工具 (MySQL `pt-index-usage`、PG `pg_stat_statements` + `hypopg`、SQL Server DTA)。

統計信息維護 (所有 RDBMS 通用)

-- DB2
RUNSTATS ON TABLE schema.table WITH DISTRIBUTION AND DETAILED INDEXES ALL;

-- MySQL
ANALYZE TABLE tbl_name;          -- 輕量
ANALYZE TABLE tbl_name UPDATE HISTOGRAM; -- 8.0+ 直方圖

-- PostgreSQL
ANALYZE [VERBOSE] [table];

-- SQL Server
UPDATE STATISTICS schema.table WITH FULLSCAN;

統計過期 = 優化器盲目 = 執行計畫災難。納入定時任務 (每日/每周)。

鐵律三:利用 OLAP 函數優化分頁 — 徹底消除「全表掃描 + 應用層分頁」

傳統 DataGrid 預設分頁災難

  • 查詢 10,000 行 → 傳輸 10,000 行 → 應用層只顯示第 3 頁 (20 行) → **99.8% 資源浪費**。
  • 百萬行表 → 記憶體溢出 / 超時 / 鎖爭用。

DB2 ROW_NUMBER() OVER() 窗口函數方案

SELECT * FROM (
  SELECT KEYCOL, COL1, COL2, COL7,
         ROW_NUMBER() OVER (ORDER BY KEYCOL ASC) AS rn
  FROM LOTSOFRECORDS
) AS t
WHERE t.rn BETWEEN 21 AND 40;  -- 第 2 頁,每頁 20 行

通用分頁模板 (參數化)

-- 參數: @PageNo (1-based), @PageSize
DECLARE @StartRow INT = (@PageNo - 1) * @PageSize + 1;
DECLARE @EndRow INT = @StartRow + @PageSize - 1;

SELECT * FROM (
  SELECT KEYCOL, COL1, COL2, COL7,
         ROW_NUMBER() OVER (ORDER BY KEYCOL ASC) AS rn
  FROM LOTSOFRECORDS
) AS t
WHERE t.rn BETWEEN @StartRow AND @EndRow;

各數據庫分頁語法對照

查詢模式耗時網絡傳輸備註
SELECT * FROM LOTSOFRECORDS1.622s~10MB全欄位、全行傳輸
SELECT KEYCOL, COL1, COL2, COL7 FROM LOTSOFRECORDS1.311s (81%)~4MB (40%)僅需欄位、索引覆蓋可能
數據庫語法版本要求
DB2 / Oracle / PostgreSQL / SQL Server 2012+OFFSET ... FETCH NEXT ... / ROW_NUMBER() 窗口函數標準 SQL:2008
MySQL 8.0+LIMIT ... OFFSET ... / 窗口函數8.0+
MySQL 5.7LIMIT ... OFFSET ... (大偏移慢)游標分頁優化

實測效能提升

  • 預設分頁:0.9-1.5s (全表掃描 + 傳輸)
  • 窗口函數分頁:0.5-0.7s (索引掃描 + 僅傳輸目標頁)
  • **資源佔用降至 0.2%**,線性擴展支撐百萬/億級表。

鐵律四:存儲過程 — 將邏輯下沉至數據庫內核

執行路徑對比

階段動態 SQL存儲過程
語法解析每次執行創建時一次
計畫生成每次執行 (可緩存)創建時編譯優化
網絡傳輸完整 SQL 文本過程名 + 參數 (極小)
權限檢查每次表級檢查過程級 EXECUTE 權限

DB2 存儲過程範例 (帶參數、返回游標)

CREATE PROCEDURE GET_PRODUCTS_IN_CATEGORY (IN CATCODE INTEGER)
DYNAMIC RESULT SETS 1
LANGUAGE SQL
P1: BEGIN
  DECLARE C1 CURSOR WITH RETURN FOR
    SELECT PRODUCTCODE, PRODUCTNAME, DESCRIPTION, UNITPRICE, IMAGEURL
    FROM PRODUCTLIST
    WHERE CATEGORYCODE = CATCODE;
  OPEN C1;
END P1

.NET 調用模式 (Borland Data Provider / ADO.NET 通用)

BdpCommand cmd = new BdpCommand("GET_PRODUCTS_IN_CATEGORY", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("CATCODE", BdpType.Integer).Value = categoryCode;

BdpDataAdapter da = new BdpDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "Products");
dataGrid.DataSource = ds;

適用性邊界

  • ✅ 複雜業務邏輯、多步事務、高頻調用、安全敏感 (隱藏表結構)。
  • ❌ 簡單 CRUD、動態構建查詢、結果集極小 (開銷不抵收益)、團隊缺乏 DBA 技能。

鐵律五:緩存為王 — 記憶體速度碾壓磁盤/網絡

ASP.NET Cache 物件三大模式

// 1. 頁面級輸出緩存 (最簡單)
<%@ OutputCache Duration="60" VaryByParam="none" %>

// 2. 數據緩存 (程式化控制)
if (Cache["Categories"] == null) {
    // 從 DB 讀取
    DataSet ds = GetCategoriesFromDB();
    // 插入緩存,6 小時絕對過期
    Cache.Insert("Categories", ds, null, 
                 DateTime.Now.AddHours(6), Cache.NoSlidingExpiration);
} else {
    ds = (DataSet)Cache["Categories"];
}

// 3. 依賴緩存 (文件/鍵/聚合依賴)
Cache.Insert("Products", ds, 
             new SqlCacheDependency("connStr", "ProductsTable")); // SQL Server 專用
// 或文件依賴
Cache.Insert("Config", configObj, new CacheDependency("config.xml"));

緩存策略決策矩陣

數據特性緩存策略過期/淘汰一致性保障
極少變更 (字典/配置)應用啟動載入、長期駐留文件依賴/手動刷新強一致
低頻變更 (商品分類)定時過期 (小時/天)AbsoluteExpiration最終一致 (業務可接受)
高頻讀、低頻寫 (用戶資料)Write-Through / Read-ThroughSlidingExpiration (20min)緩存旁路更新 DB 同步刪除
高頻讀寫 (庫存/計數器)**不緩存** 或 Redis 原子操作N/A強一致 (DB 為準)

分散式緩存升級 (Redis / Memcached)

  • 解決單機記憶體上限、多實例緩存不一致、重啟預熱問題。
  • StackExchange.Redis / EnyimMemcached 客戶端支援連接池、管道、Lua 腳本原子操作。
  • 緩存穿透/擊穿/雪崩防護:布隆過濾器、互斥鎖重建、隨機過期時間。

總結:從五大鐵律到工程體系

  1. 按需檢索 → 代碼審查強制 `SELECT` 列清單,禁止 `*`。
  2. 優化數據庫 → 索引變更走變更流程,統計信息納入定時任務,慢查詢日誌每日分析。
  3. OLAP 分頁 → 框架封裝通用分頁組件,禁止手寫 `OFFSET` 大偏移。
  4. 存儲過程 → 核心交易邏輯下沉,應用層僅調用,版本管理納入 Git (SQL 腳本)。
  5. 緩存分層 → 本地緩存 (熱點小數據) + 分散式緩存 (共享大數據) + CDN (靜態資源),統一緩存鍵命名規範。

這五大鐵律不是孤立技巧,而是構建**高效能、可擴展、可維護**數據訪問層的基因密碼。將其內化為團隊開發規範、CI/CD 檢查門禁、架構評審核心指標,才能真正實現「優秀的代碼行行相似」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved