首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

SQL Server 查詢計畫快取記憶體消耗分析:參數化查詢 vs 臨時查詢的實測對比

     編輯:關於SqlServer

應用程式若大量使用非參數化臨時查詢,會導致計畫快取膨脹、記憶體壓力大增、CPU 反覆編譯。本文透過 Java 程式碼模擬 20 筆非參數化與參數化查詢,配合 DMV SYS.DM_EXEC_CACHED_PLANS 實測快取佔用差異,量化記憶體與 CPU 影響,並說明預存程序為最佳實務。

場景模擬

  • 目標表:ADVENTUREWORKS.SALES.SALESORDERHEADER。
  • 查詢:依 SALESORDERID 擷取訂單資料,ID 1~20。
  • 對比:非參數化字串拼接 vs PREPARED STATEMENT (參數化) vs 預存程序。

非參數化臨時查詢 (錯誤示範)

// Java 片段
for (int i = 1; i <= 20; i++) {
    String sql = "SELECT * FROM SALESORDERHEADER WHERE SALESORDERID = " + i;
    stmt.executeQuery(sql);  // 每次產生新查詢文字
}

DMV 查詢快取

SELECT QS.USECOUNTS, QS.CACHEOBJTYPE, QS.OBJTYPE, QT.TEXT
FROM SYS.DM_EXEC_CACHED_PLANS QS
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(QS.PLAN_HANDLE) QT
ORDER BY QT.TEXT;

結果

  • 產生 20 個獨立計畫 (OBJTYPE = ADHOC),USECOUNTS = 1。
  • 每個計畫佔用 ~24KB 快取記憶體,總計 ~480KB。
  • 若每秒 1000 此類查詢,快取將在數分鐘內佔用數 GB 記憶體,觸發記憶體壓力、計畫驅逐、CPU 飆升。

參數化查詢 / PreparedStatement (改善)

String sql = "SELECT * FROM SALESORDERHEADER WHERE SALESORDERID = ?";
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 1; i <= 20; i++) {
    ps.setInt(1, i);
    ps.executeQuery();
}

結果

  • 單一計畫 (OBJTYPE = PREPARED),USECOUNTS = 20。
  • 快取記憶體 ~24KB,CPU 編譯成本僅 1 次。
  • 計畫重用率 100%。

預存程序 (最佳實務)

CREATE PROC USP_GET_ORDER @ORDERID INT
AS SELECT * FROM SALESORDERHEADER WHERE SALESORDERID = @ORDERID;
  • 計畫物件類型 PROC,參數嗅探優化、權限封裝、維護性最高。
  • 應用層呼叫:EXEC USP_GET_ORDER @ORDERID = ?。

三種模式量化對比

DMV 監控腳本:偵測臨時查詢氾濫

-- 找出 USECOUNTS=1 的 ADHOC 計畫 (疑似臨時查詢)
SELECT TOP 50 
    QT.TEXT, QS.USECOUNTS, QS.SIZE_IN_BYTES/1024.0 AS KB
FROM SYS.DM_EXEC_CACHED_PLANS QS
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(QS.PLAN_HANDLE) QT
WHERE QS.OBJTYPE = 'ADHOC' AND QS.USECOUNTS = 1
ORDER BY QS.SIZE_IN_BYTES DESC;

-- 整體快取佔用摘要
SELECT OBJTYPE, COUNT(*) AS PLAN_COUNT, SUM(SIZE_IN_BYTES)/1024/1024 AS TOTAL_MB
FROM SYS.DM_EXEC_CACHED_PLANS
GROUP BY OBJTYPE;

最佳實務建議

  1. ✅ 預設使用預存程序,封裝邏輯、權限最小化、計畫穩定。
  2. ✅ 若必須動態 SQL,強制參數化 (SP_EXECUTESQL / PreparedStatement)。
  3. ✅ 啟用 OPTIMIZE FOR AD HOC WORKLOADS (SQL 2008+):首次執行僅快取計畫存根,第二次才完整快取,減少一次性查詢佔用。
    EXEC SP_CONFIGURE 'SHOW ADVANCED OPTIONS', 1; RECONFIGURE;
    EXEC SP_CONFIGURE 'OPTIMIZE FOR AD HOC WORKLOADS', 1; RECONFIGURE;
  4. ✅ 定期執行 DBCC FREEPROCCACHE (維護窗口) 或針對特定計畫 DBCC FLUSHPROCINDB。
  5. ✅ 監控 SQLServer:Plan Cache 計數器,設定警示於 Cache Hit Ratio < 90% 時通知。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
指標非參數化臨時查詢PreparedStatement預存程序
計畫數量 (20 次執行)2011
快取記憶體~480 KB~24 KB~24 KB
編譯 CPU20 次1 次1 次
計畫重用率0%100%100%
防注入無有有
權限控管需表權限需表權限僅需 EXEC 權限
維護性差 (SQL 散落應用層)中佳 (集中資料層)