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

SQL Server 預存程序實戰精要:ALTER vs CREATE、輸出參數陷阱、優缺點權衡與動態 SQL

     編輯:關於SqlServer

預存程序是資料庫邏輯封裝的核心單元。本文聚焦實戰易踩坑:ALTER/CREATE 差異、輸出參數雙重 OUTPUT、EXEC 作用域隔離、動態 SQL 注入防範、效能計畫快取陷阱。

一、ALTER PROCEDURE vs CREATE PROCEDURE

差異點CREATEALTER
物件存在性不存在才能建立必須已存在
權限保留重建後權限遺失保留原有 GRANT/DENY
Object ID新 ID同一 ID,相依物件不失效
相依關係中斷保留

最佳實務: 部署腳本統一用 IF EXISTS ... DROP ... CREATE 或 CREATE OR ALTER(SQL Server 2016 SP1+),避免權限遺失。

二、輸出參數:雙重 OUTPUT 鐵律

-- 定義
CREATE PROC dbo.GetOrderCount @CustomerID INT, @Total INT OUTPUT
AS
  SELECT @Total = COUNT(*) FROM Orders WHERE CustomerID = @CustomerID;
GO

-- 呼叫:定義與呼叫「雙方」都要加 OUTPUT
DECLARE @Cnt INT;
EXEC dbo.GetOrderCount @CustomerID = 123, @Total = @Cnt OUTPUT;  -- ← 這裡必須加 OUTPUT
PRINT @Cnt;

⚠ 呼叫端漏寫 OUTPUT:不報錯、不回傳值、變數保持 NULL,極難除錯。

三、EXEC 執行陷阱

  1. 作用域隔離:EXEC 內的變數外部不可見,外部變數需轉字串拼接才能傳入(或用 sp_executesql 參數化)
  2. 安全內容:預設以呼叫者身分執行,而非擁有者(模組簽名/EXECUTE AS 可改變)
  3. 同一連線/交易:與呼叫者共享連線與交易巢狀層級
  4. 字串拼接順序:動態 SQL 字串必須在 EXEC 前組裝完成,不可在同一批次中邊組裝邊執行
  5. 不可用於 UDF 內:純量/表值函數禁止 EXEC

四、動態 SQL 安全模板

CREATE PROC dbo.SearchOrders @Keyword NVARCHAR(100), @Status TINYINT = NULL
AS
BEGIN
    DECLARE @sql NVARCHAR(MAX) = N'
        SELECT OrderID, CustomerID, Status, CreatedAt
        FROM dbo.Orders
        WHERE 1=1';
    DECLARE @params NVARCHAR(MAX) = N'@Keyword NVARCHAR(100), @Status TINYINT';

    IF @Keyword IS NOT NULL
        SET @sql += N' AND (CustomerName LIKE @Keyword + N''%'' OR OrderNo LIKE @Keyword + N''%'')';
    IF @Status IS NOT NULL
        SET @sql += N' AND Status = @Status';

    EXEC sp_executesql @sql, @params, @Keyword, @Status;
END;

✅ sp_executesql 參數化 → 計畫重用 + 防注入 + 型別安全。

五、預存程序優缺點權衡

優點缺點
效能:計畫快取、減少網路往返平台鎖定:Oracle/PostgreSQL 語法差異大
安全:權限隔離、防 SQL 注入計畫參數嗅探導致錯誤計畫(參數值變化大時)
可重用:業務邏輯集中、版本控管除錯困難、缺乏單元測試工具鏈
封裝:隱藏結構、減少表直接暴露版本部署需協調 DBA、應用端

六、參數嗅探應對策略

  • OPTION (RECOMPILE):每次重新編譯,適用高變異度、低頻程序
  • OPTION (OPTIMIZE FOR @param = 'typical_value'):指定典型值
  • 區域變數賦值:DECLARE @local = @param; ... WHERE col = @local(優化器視為未知值,走平均密度)
  • 查詢存儲 啟用後可強制計畫

結語: 預存程序是利器,但需建立「命名規範、參數化動態 SQL、計畫監控、自動化部署」四大工程化配套,才能發揮最大效益。

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