預存程序(Stored Procedure,SP)封裝複雜業務邏輯與資料庫操作,減少網路往返、提升安全性、便於維護。但 SP 數量龐大、缺乏規範、或忽視效能優化時,將導致系統難以維護、效能低落。經實測,優化後的 SP 效能可達未優化版本的數百倍。本文針對大數據量、高併發 OLTP 系統,提供開發規範與優化實戰指南。
原則:跨資料庫存取必須在當前資料庫建立 View,嚴禁直接使用
database.dbo.table_name寫法。
sp_depends 無法追蹤跨庫相依關係,影響影響分析與重構V_EXT_<來源DB>_<表名>SET SHOWPLAN ON 檢視每條 SQL 計劃,確無全表掃描、索引缺失、Cardinality 嚴重偏差HOLDLOCK(等同 SERIALIZABLE),嚴重降低並發EXISTS 替代 IN / COUNT(*) 判斷存在性FAST_FORWARD(唯讀、順向)遊標,效能最佳WHERE TRUNC(dt) = ... ❌ → WHERE dt >= ... AND dt < ... ✅>= 優於 >(邊界包含語意更清晰,優化器估算更準)OR 條件評估改寫為 UNION ALL(互斥集合)或 IN 列表COUNT(1) 優於 COUNT(*)(舊版本有差異,新版本相同,習慣用 1)EXISTS (SELECT 1 ...),嚴禁 SELECT COUNT(*) > 0ALTER INDEX ... REBUILD)與重新編譯 SP(DBMS_UTILITY.COMPILE_SCHEMA)V$OBJECT_USAGE 識別未使用索引並移除DISTINCT、ORDER BY、GROUP BY、HAVING、JOIN、COMPUTE 等加重 TempDB 負擔的操作SELECT INTO 避免 Log、提速;小量資料:CREATE TABLE + INSERT 緩和系統表壓力TRUNCATE TABLE → DROP TABLE,避免系統表長時間鎖定SET STATISTICS IO ON; -- 邏輯/物理讀取
SET STATISTICS TIME ON; -- CPU/經過時間
SET SHOWPLAN ON; -- 執行計劃(不執行)
Logical Reads、Physical Reads、CPU Time、Elapsed Time 選擇最優方案OUT / IN OUTCREATE OR REPLACE PROCEDURE PROC_EXAMPLE (
P_ID IN NUMBER,
P_RESULT OUT VARCHAR2
) AS
V_ERR_CODE NUMBER;
V_ERR_MSG VARCHAR2(4000);
BEGIN
-- 業務邏輯
UPDATE TABLE_A SET COL1 = 'X' WHERE ID = P_ID;
IF SQL%NOTFOUND THEN
P_RESULT := 'NOT_FOUND';
RETURN;
END IF;
COMMIT;
P_RESULT := 'SUCCESS';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
V_ERR_CODE := SQLCODE;
V_ERR_MSG := SUBSTR(SQLERRM, 1, 4000);
-- 寫入稽核表
INSERT INTO PROC_AUDIT_LOG (PROC_NAME, ERR_CODE, ERR_MSG, CALL_TIME)
VALUES ('PROC_EXAMPLE', V_ERR_CODE, V_ERR_MSG, SYSDATE);
COMMIT;
P_RESULT := 'ERROR:' || V_ERR_CODE;
END;
| 類別 | 檢核項目 | 嚴重度 |
|---|---|---|
| 跨庫存取 | 是否透過 View 存取,無硬編碼 DB Link | 高 |
| 執行計劃 | 所有 SQL 已驗證無全表掃描、索引缺失 | 最高 |
| 遊標使用 | 無遊標或遊標<1萬列且迴圈無聯結 | 高 |
| WHERE 條件 | 索引欄位無函數、順序正確、無隱含轉換 | 最高 |
| 暫存表 | 大量用 SELECT INTO、建索引獨立子程序、結束顯式清理 | 中 |
| 索引維護 | 定期重建、移除未用索引、監控使用率 | 中 |
| 參數命名 | 無與欄位同名、型別完全一致 | 高 |
| 錯誤處理 | 有 EXCEPTION 區塊、稽核記錄、交易回滾 | 高 |
將此檢核表納入 Code Review 流程,能攔截 90% 以上的 SP 效能與維護隱患。