CLR 整合架構 - 效能

適用於:SQL ServerAzure SQL 受控執行個體

本主題討論一些設計選擇,這些選項可增強 Microsoft SQL Server與 Microsoft .NET Framework Common Language Runtime (CLR) 的整合。

編譯程序

在 SQL 運算式編譯期間,遇到 Managed 常式的參考時,會產生 Microsoft 中繼語言 (MSIL) 存根。 此存根包含程式碼,可將常式參數從SQL Server封送處理至 CLR、叫用函式,以及傳回結果。 這個「黏附」程式碼是以參數類型以及參數方向 (in、out 或參考) 為基礎。

黏附程式碼會啟用類型特定的優化,並確保有效率地強制執行SQL Server語意,例如可為 Null、限制 Facet、依值和標準例外狀況處理。 透過產生正確引數類型的程式碼,您可以跨引動過程界限避免強制型轉或包裝函數物件建立成本 (稱為「Boxing」)。

然後,產生的存根會編譯為機器碼,並針對SQL Server執行的特定硬體架構進行優化,並使用 (CLR 的 Just-In-Time) 編譯服務。 JIT 服務會在方法層級叫用,並允許SQL Server裝載環境建立跨越SQL Server和 CLR 執行的單一編譯單位。 一旦虛設常式經過編譯之後,所產生的函數指標就會變成函數的執行階段實作。 這個程式碼產生方法可確保沒有與執行階段存取之反射或中繼資料相關的其他引動過程成本。

在 SQL Server 和 CLR 之間快速轉換

編譯程序會產生可以在執行階段,從原生程式碼呼叫的函數指標。 如果是純量值的使用者定義函數,此函數引動過程會以資料列為基礎發生。 若要將SQL Server與 CLR 之間轉換的成本降到最低,包含任何受控調用的語句都有啟動步驟來識別目標應用程式域。 這個識別步驟會降低每個資料列轉換的成本。

效能考量

下列摘要說明SQL Server中 CLR 整合特有的效能考慮。 More detailed information can be found in "Using CLR Integration in SQL Server 2005" on the MSDN Web site. General information regarding managed code performance can be found in "Improving .NET Application Performance and Scalability" on the MSDN Web site.

使用者定義的函式

CLR 函式受益于比 Transact-SQL 使用者定義函式更快速的調用路徑。 此外,Managed 程式碼在程式碼、計算和字串操作方面,具有 Transact-SQL 的效能優勢。 需要大量計算而不執行資料存取的 CLR 函數以更好的 Managed 程式碼方式撰寫。 不過,Transact-SQL 函式會比 CLR 整合更有效率地執行資料存取。

使用者定義彙總

Managed 程式碼可能明顯優於資料指標型彙總。 Managed 程式碼的執行速度通常比內建SQL Server彙總函式慢一點。 建議您在原生的內建彙總函式存在時使用它。 如果是原本不支援所需彙總的地方,請就效能上,考慮透過資料指標型實作使用 CLR 使用者定義彙總。

資料流資料表值函式

應用程式通常需要傳回資料表做為叫用函數的結果。 範例包含在匯入作業期間從檔案讀取表格式資料,以及將逗號分隔值轉換成關聯式表示。 您通常可以先透過具體化與擴展結果資料表來完成這個動作,然後再讓呼叫端取用。 CLR 與 SQL Server整合引進稱為串流資料表值函式的新擴充性機制, (STVF) 。 Managed STVF 的執行效能比可比較的擴充預存程序實作更好。

STFS 是傳回 IEnumerable 介面的 Managed 函式。 IEnumerable 有方法可巡覽 STVF 傳回的結果集。 叫用 STVF 時,傳回的 IEnumerable 會直接連線到查詢計劃。 查詢計劃需要擷取資料列時,會呼叫 IEnumerable 方法。 此反覆運算模型可在產生第一個資料列之後,立即取用結果,而不會等到擴充整個資料表。 它也會大幅減少叫用函數所耗用的記憶體。

陣列與資料指標的比較

當 Transact-SQL 資料指標必須周遊更容易以陣列表示的資料時,Managed 程式碼可以搭配大幅效能提升使用。

字串資料

SQL Server Varchar之類的字元資料可以是 Managed 函式中的 SqlString 或 SqlChars 類型。 SqlString 變數會在記憶體中建立整個值的執行個體。 SqlChars 變數會提供資料流介面,不需要透過在記憶體中建立整個值的執行個體,就可以用於達到更好的效能與延展性。 這對於大型物件 (LOB) 資料而言,變得特別重要。 此外,伺服器 XML 資料也可以透過 SqlXml.CreateReader () 傳回的串流介面來存取。

CLR 與擴充預存程序的比較

允許 Managed 程序將結果集傳回用戶端之 Microsoft.SqlServer.Server 應用程式開發介面 (API) 的執行效能比擴充預存程序所使用的開放式資料服務 (ODS) API 更好。 此外,System.Data.SqlServer API 支援xmlVarchar (max) Nvarchar (max ) 和Varbinary (max ) 中所引進的資料類型,SQL Server 2005 (9.x) ,而 ODS API 尚未擴充以支援新的資料類型。

使用 Managed 程式碼時,SQL Server管理資源的使用,例如記憶體、執行緒和同步處理。 這是因為公開這些資源的受控 API 會在SQL Server資源管理員之上實作。 相反地,SQL Server沒有檢視或控制擴充預存程式的資源使用量。 例如,如果擴充預存程式耗用太多 CPU 或記憶體資源,則無法透過SQL Server來偵測或控制此專案。 不過,使用 Managed 程式碼時,SQL Server可以偵測到指定的執行緒尚未產生很長的時間,然後強制工作產生,以便排程其他工作。 因此,使用 Managed 程式碼可以提供較佳的延展性與系統資源使用量。

Managed 程式碼可能會產生維護執行環境與執行安全性檢查所需的額外負擔。 例如,在SQL Server內執行時,需要許多從 Managed 轉換到機器碼的轉換 (,因為SQL Server在移出至機器碼和返回) 時,需要對執行緒特定設定執行額外的維護。 因此,擴充預存程式對於 Managed 和機器碼之間經常轉換的情況,在SQL Server內執行之 Managed 程式碼可能會明顯優於執行。

注意

建議您不要開發新的擴充預存程序,因為此功能已被取代。

使用者定義型別的原生序列化

使用者定義型別 (UDT) 會針對純量類型系統,設計成一個擴充性機制。 SQL Server實作名為Format.Native的 UDT 序列化格式。 在編譯期間,系統會檢查類型的結構來產生針對該特定類型定義自訂的 MSIL。

原生序列化是SQL Server的預設實作。 使用者定義序列化會叫用類型作者所定義的方法來進行序列化。 Format.Native 序列化應該盡可能使用,以獲得最佳效能。

可比較 UDT 的正規化

排序和比較 UDT 之類的關聯式作業會直接針對值的二進位表示操作。 這會透過將 UDT 狀態的正規化 (二進位排序) 表示儲存在磁碟上完成。

正規化有兩個優點:它會透過避免類型執行個體的建構以及方法引動過程負擔,讓比較作業的成本變得相當低;而且它會建立 UDT 的二進位網域,以便建構長條圖、索引,以及類型值的長條圖。 因此,正規化的 UDT 與不包含方法引動過程作業的原生內建類型,擁有非常類似的效能設定檔。

可擴充的記憶體使用量

為了讓受控垃圾收集在SQL Server中執行和調整良好,請避免大型、單一配置。 其大小大於 88 KB 的配置將會放在大型物件堆積上,這會讓記憶體回收的執行與調整比許多較小的配置差很多。 例如,如果您需要配置大型的多維度陣列,最好配置不規則 (散佈) 陣列。

另請參閱

CLR 使用者定義類型