應用程式若大量使用非參數化臨時查詢,會導致計畫快取膨脹、記憶體壓力大增、CPU 反覆編譯。本文透過 Java 程式碼模擬 20 筆非參數化與參數化查詢,配合 DMV SYS.DM_EXEC_CACHED_PLANS 實測快取佔用差異,量化記憶體與 CPU 影響,並說明預存程序為最佳實務。
ADVENTUREWORKS.SALES.SALESORDERHEADER。SALESORDERID 擷取訂單資料,ID 1~20。PREPARED STATEMENT (參數化) vs 預存程序。// Java 片段
for (int i = 1; i <= 20; i++) {
String sql = "SELECT * FROM SALESORDERHEADER WHERE SALESORDERID = " + i;
stmt.executeQuery(sql); // 每次產生新查詢文字
}
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;
OBJTYPE = ADHOC),USECOUNTS = 1。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。CREATE PROC USP_GET_ORDER @ORDERID INT
AS SELECT * FROM SALESORDERHEADER WHERE SALESORDERID = @ORDERID;
PROC,參數嗅探優化、權限封裝、維護性最高。EXEC USP_GET_ORDER @ORDERID = ?。| 指標 | 非參數化臨時查詢 | PreparedStatement | 預存程序 |
|---|---|---|---|
| 計畫數量 (20 次執行) | 20 | 1 | 1 |
| 快取記憶體 | ~480 KB | ~24 KB | ~24 KB |
| 編譯 CPU | 20 次 | 1 次 | 1 次 |
| 計畫重用率 | 0% | 100% | 100% |
| 防注入 | 無 | 有 | 有 |
| 權限控管 | 需表權限 | 需表權限 | 僅需 EXEC 權限 |
| 維護性 | 差 (SQL 散落應用層) | 中 | 佳 (集中資料層) |