SQL Server 2005 引入 CLR 整合 (CLR Integration),在資料庫引擎內託管 .NET Framework 2.0 CLR,允許以 C#、VB.NET、C++ 撰寫預存程序、觸發器、使用者定義函數 (UDF)、使用者定義型別 (UDT)、使用者定義彙總 (UDA)。這打破 T-SQL 在複雜運算、正則表達式、加密、檔案操作、Web Service 呼叫等領域的表達力限制,實現資料層邏輯與應用層共用程式碼庫。
-- 啟用 CLR (預設關閉)
EXEC sp_configure 'clr enabled', 1; RECONFIGURE;
安全權限集 (Permission Set):
| 權限集 | 能力 | 適用場景 |
|---|---|---|
| SAFE (預設) | 僅記憶體運算、資料存取、無外部存取 | 純運算邏輯、字串處理、數學函數 |
| EXTERNAL_ACCESS | 讀寫檔案、網路、登錄、環境變數 | 檔案處理、Web Service 呼叫、事件日誌 |
| UNSAFE | 非受控程式碼、P/Invoke、靜態變數、執行緒控制 | 極少數極複雜場景,需嚴格審核 |
部署單位:組件。簽署強名稱或憑證,建立非對稱金鑰/憑證登入,授予對應權限集。
[SqlProcedure]、[SqlFunction]、[SqlTrigger] 等。[SqlFunction(DataAccess = DataAccessKind.Read)]
public static SqlInt32 CountOrdersByCustomer(SqlString customerId)
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
SqlCommand cmd = new SqlCommand(
"SELECT COUNT(*) FROM Orders WHERE CustomerID = @cid", conn);
cmd.Parameters.AddWithValue("@cid", customerId);
return (int)cmd.ExecuteScalar();
}
}
.dll 組件、.pdb 偵錯符號。CREATE ASSEMBLY、CREATE PROCEDURE/FUNCTION...,上傳組件二進位、原始碼、PDB 至資料庫。| 維度 | T-SQL | CLR 整合 | 擴充預存程序 (XP) |
|---|---|---|---|
| 語言 | T-SQL | C#/VB.NET/C++ | C/C++ (非受控) |
| 型別系統 | 內建標量/表格 | 豐富 .NET 型別 + UDT | 自行管理 |
| 效能:集合運算 | 極佳 (集合導向) | 良好 (需避免逐列) | 視實作而定 |
| 效能:複雜純量運算 | 差 (解譯執行) | 極佳 (JIT 編譯原生碼) | 極佳 |
| 外部資源存取 | 受限 (OPENROWSET/OLE DB) | EXTERNAL_ACCESS 安全管控 | 完全自由 (高風險) |
| 部署/版本 | 腳本部署 | 組件版本、強名稱、PDB | DLL 地獄、難版控 |
| 偵錯 | PRINT/RAISERROR、Profiler | VS 完整偵錯器 | 極難 (需核心偵錯) |
| 安全性 | 權限模型成熟 | 三層權限集、代碼存取安全性 (CAS) | 無沙箱、極高風險 |
| 相容性 | 所有版本 | SQL Server 2005+ | 所有版本 (已棄用) |
SqlDataReader 批次讀取或改寫為 T-SQL 集合邏輯。context connection=true 重用現有連線,不可開啟交易、不可多重作用中巢狀 (MARS 除外)。外部連線用一般連線字串。ALTER ASSEMBLY ... WITH VISIBILITY ON/OFF,搭配強名稱簽署,避免 DLL Hell。sys.dm_clr_appdomains、sys.dm_clr_loaded_assemblies、sys.dm_clr_tasks、sys.dm_os_memory_clerks (type = 'CLR')。[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToNulls = true,
IsInvariantToDuplicates = false, IsInvariantToOrder = false, MaxByteSize = -1)]
public struct Median : IBinarySerialize
{
private List _values;
public void Init() { _values = new List(); }
public void Accumulate(SqlDouble value) { if (!value.IsNull) _values.Add(value.Value); }
public void Merge(Median other) { _values.AddRange(other._values); }
public SqlDouble Terminate()
{
if (_values.Count == 0) return SqlDouble.Null;
_values.Sort();
int mid = _values.Count / 2;
return _values.Count % 2 == 0
? (_values[mid - 1] + _values[mid]) / 2.0
: _values[mid];
}
public void Read(System.IO.BinaryReader r) { /* 反序列化 */ }
public void Write(System.IO.BinaryWriter w) { /* 序列化 */ }
}
使用:SELECT dbo.Median(Score) FROM Exams GROUP BY Class;
CLR 整合將 .NET 生態系統的強大威力帶入資料庫核心,但權力越大、責任越大。遵循「T-SQL 優先、CLR 補位、權限最小、偵錯優先、監控常態」原則,即能在保障穩定安全的前提下,釋放資料層運算的無限潛能。