CLR 整合架構的效能
適用於:SQL Server Azure SQL 受控執行個體
本文討論一些可增強 SQL Server 與 Microsoft .NET Framework Common Language Runtime (CLR) 整合效能的設計選擇。
編譯程式
在 SQL 運算式編譯期間,遇到 Managed 例程的參考時,會產生Microsoft中繼語言 (MSIL) 存根。 此存根包含程式代碼,可將例程參數從 SQL Server 封送處理至 CLR、叫用函式,以及傳回結果。 此「黏附」程序代碼是以參數類型為基礎,以及參數方向(in、out 或 reference)。
黏附程式代碼會啟用類型特定的優化,並確保有效率地強制執行 SQL Server 語意,例如可為 Null 性、限制 Facet、依值和標準例外狀況處理。 藉由為自變數的確切類型產生程式代碼,您可以避免跨調用界限產生類型強制或包裝函式物件建立成本(稱為「Boxing」)。
產生的存根接著會編譯為原生程式代碼,並使用CLR的Just-In-Time (JIT) 編譯服務,針對SQL Server 執行的特定硬體架構進行優化。 JIT 服務會在方法層級叫用,並允許 SQL Server 裝載環境建立跨越 SQL Server 和 CLR 執行的單一編譯單位。 編譯存根之後,產生的函式指標會變成函式的運行時間實作。 此程式代碼產生方法可確保運行時間沒有與反映或元數據存取相關的額外調用成本。
SQL Server 與 CLR 之間的快速轉換
編譯程式會產生可從機器碼在運行時間呼叫的函式指標。 對於純量值使用者定義函式,此函式調用會以每個數據列為基礎進行。 若要將 SQL Server 與 CLR 之間的轉換成本降到最低,包含任何 Managed 調用的語句都有一個啟動步驟來識別目標應用程式域。 此識別步驟可降低每個數據列轉換的成本。
效能考量
下一節摘要說明 SQL Server 中 CLR 整合特有的效能考慮。 如需詳細資訊,請參閱 在 SQL Server 2005 中使用 CLR 整合。 如需 Managed 程式代碼效能的相關信息,請參閱 改善 .NET 應用程式效能和延展性。
使用者定義的函式
CLR 函式受益於比 Transact-SQL 使用者定義函式更快的調用路徑。 此外,受控程式代碼在程式碼、計算和字串操作方面,具有比 Transact-SQL 具有決定性的效能優勢。 需要大量運算且不會執行數據存取的 CLR 函式會以 Managed 程式代碼撰寫得更好。 不過,Transact-SQL 函式會比 CLR 整合更有效率地執行數據存取。
使用者自訂彙總
受控程式代碼明顯優於數據指標型匯總。 Managed 程式代碼的執行速度通常比內建 SQL Server 聚合函數慢一點。 我們建議,如果原生內建聚合函數存在,您應該使用它。 如果原生不支援所需的匯總,請考慮基於效能考慮,透過數據指標型實作的 CLR 使用者定義匯總。
串流數據表值函式
應用程式通常需要傳回數據表,因為叫用函式。 範例包括從檔案讀取表格式數據做為匯入作業的一部分,以及將逗號分隔值轉換成關係型表示法。 一般而言,您可以藉由具體化和填入結果數據表來完成這項作業,然後呼叫端才能取用結果數據表。 CLR 與 SQL Server 整合引進了稱為串流數據表值函式 (STVF) 的新擴充性機制。 Managed STVF 的執行效能優於可比較的擴充預存程式實作。
STVF 是傳回介面的 IEnumerable
Managed 函式。 IEnumerable
有方法可巡覽 STVF 所傳回的結果集。 叫用 STVF 時,傳回的 IEnumerable
會直接連接到查詢計劃。 查詢計劃會在需要擷取數據列時呼叫 IEnumerable
方法。 此反覆專案模型可讓產生第一個數據列之後立即取用結果,而不是等到填入整個數據表為止。 它也會大幅減少叫用函式所耗用的記憶體。
陣列與數據指標
當 Transact-SQL 數據指標必須周遊更容易表示為數位資料時,Managed 程式代碼可以搭配顯著的效能提升使用。
字串資料
SQL Server 字元數據,例如 varchar,可以是 Managed 函式中的 SqlString 或 SqlChars 類型。 SqlString 變數會將整個值的實例建立到記憶體中。 SqlChars 變數提供串流介面,可用來透過不將整個值的實例建立到記憶體中,以達到更佳的效能和延展性。 對於大型物件 (LOB) 數據而言,這會變得很重要。 此外,伺服器 XML 資料也可以透過 所 SqlXml.CreateReader()
傳回的串流介面來存取。
CLR 與擴充預存程式
Microsoft.SqlServer.Server
允許 Managed 程式傳送結果集回到用戶端的應用程式程式設計介面(API),比擴充預存程式所使用的 Open Data Services (ODS) API 執行得更好。 此外,System.Data.SqlServer API 也支援 SQL Server 2005 (9.x) 中引進的 xml、varchar(max)、nvarchar(max)和 varbinary(max)等數據類型,而 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 的配置會放在大型物件堆積上,這會導致垃圾收集執行並調整比許多較小的配置更差。 例如,如果您需要配置大型多維度陣列,最好配置雜亂(散佈)陣列。