預存程序是 SQL Server 核心程式設計物件,封裝 T-SQL 邏輯、提升效能、強化安全性、促進程式碼重用。本文系統說明預存程序分類、建立與呼叫語法、參數傳遞、加密選項、權限模型、常見陷阱(物件擁有者解析、暫存程序)與實務建議,助你掌握這項關鍵技能。
| 類型 | 前綴 | 儲存位置 | 說明 |
|---|---|---|---|
| 系統預存程序 | sp_ | master | SQL Server 內建,所有資料庫均可直接呼叫。 |
| 擴充預存程序 | xp_ 或 sp_ | master (DLL) | 以 C/C++ 撰寫的外部模組,擴充引擎功能。 |
| 使用者定義預存程序 | 自訂(避免 sp_/xp_) | 使用者資料庫 | 開發人員撰寫的業務邏輯封裝。 |
注意:使用者程序勿以 sp_ 開頭,否則引擎會優先在 master 尋找,造成效能損耗與名稱衝突風險。
EXECUTE 權限,不需直接授與資料表 SELECT/INSERT/UPDATE/DELETE。WITH ENCRYPTION 隱藏定義原始碼(注意:非軍用級加密,專業工具可反編譯)。USE pubs;
GO
CREATE PROCEDURE dbo.MyProce
@param1 CHAR(4),
@param2 VARCHAR(40)
WITH ENCRYPTION
AS
BEGIN
INSERT INTO stores (stor_id, stor_name) VALUES (@param1, @param2);
END;
GO
-- 呼叫
EXEC dbo.MyProce '1111', 'Leijun Book';
CREATE PROCEDURE dbo.SearchMe
@param1 VARCHAR(10),
@param2 VARCHAR(30) OUTPUT
AS
BEGIN
SELECT @param2 = au_id
FROM authors
WHERE au_fname + au_lname = @param1;
IF @@ROWCOUNT > 0
PRINT '查有此人 ID: ' + @param2;
ELSE
PRINT '查無此人';
END;
GO
-- 呼叫
DECLARE @id VARCHAR(30);
EXEC dbo.SearchMe 'Leijun', @id OUTPUT;
PRINT @id;
| 選項 | 用途 | 備註 |
|---|---|---|
WITH ENCRYPTION | 隱藏程序定義原始碼 | sp_helptext 將無法顯示;備份時請保留原始碼。 |
WITH RECOMPILE | 每次執行重新編譯 | 適用參數嗅嚐導致計畫不穩定的情境;會增加 CPU 負載。 |
WITH EXECUTE AS | 指定執行內容 | CALLER (預設)、SELF、OWNER、'user';解決跨資料庫/伺服器權限問題。 |
ALTER PROCEDURE 保留權限與相依性。sp_helptext 'dbo.ProcName' 或 SSMS 物件總管右鍵「修改」。DROP PROCEDURE dbo.ProcName。sp_recompile 'dbo.ProcName' 標記下次執行重新編譯。下列 DDL 陳述式不可在預存程序中使用:
CREATE DEFAULT, CREATE TRIGGER, CREATE PROCEDURE, CREATE VIEW, CREATE RULE
若 SQL 陳述式未指定 Schema(如 SELECT * FROM Sample),執行時解析順序為:
dbo Schema。最佳實踐:永遠使用兩部分名稱 Schema.Object(如 dbo.Sample),避免解析歧義與計畫快取汙染。
| 前綴 | 範圍 | 生命週期 |
|---|---|---|
#ProcName | 工作階段 (Session) | 建立者 Session 結束自動刪除 |
##ProcName | 全域 (所有 Session) | 建立者 Session 結束且無其他參考時刪除 |
適用於動態產生、一次性邏輯,避免永久物件汙染目錄。
-- 僅授與執行權限,不需資料表直接權限
GRANT EXECUTE ON dbo.MyProce TO AppUser;
REVOKE EXECUTE ON dbo.MyProce FROM AppUser;
預存程序是 SQL Server 開發的基石。掌握分類、參數化、加密、Schema 前綴、權限最小化、避免禁用 DDL、善用暫存程序等要訣,能讓資料層程式碼更安全、高效、可維護。建議在專案規範中強制要求:
Schema.Object。sp_recompile 關鍵程序應對統計變更。