趣談CLR集成性能設(shè)計選擇
本文主要討論了一些提高 Microsoft SQL Server 與 Microsoft .NET Framework 公共語言運行時 CLR集成性能的設(shè)計選擇。希望對大家有幫助。
1.編譯過程
在編譯 SQL 表達(dá)式時,如果遇到對托管例程的引用,則生成 Microsoft 中間語言 (MSIL) 存根。該存根包含的代碼用于將例程參數(shù)從 SQL Server 封送到 CLR、調(diào)用函數(shù)并返回結(jié)果。該“粘附”代碼基于參數(shù)類型和參數(shù)方向(向內(nèi)、向外或引用)。粘附代碼支持特定于類型的優(yōu)化,并確保有效地強(qiáng)制實現(xiàn) SQL Server 語義,例如為 Null 性、約束方面、按值和標(biāo)準(zhǔn)異常處理。通過為確切類型的參數(shù)生成代碼,可以避免跨調(diào)用邊界的類型強(qiáng)制或包裝對象創(chuàng)建開銷(稱為“裝箱”)。隨后,使用 CLR 的 JIT(實時)編譯服務(wù)將生成的存根編譯為本機(jī)代碼,并針對 SQL Server 執(zhí)行所在的特定硬件體系結(jié)構(gòu)進(jìn)行優(yōu)化。JIT 服務(wù)是在方法級別調(diào)用的,并允許 SQL Server 宿主環(huán)境創(chuàng)建一個跨 SQL Server 和 CLR 執(zhí)行的編譯單元。編譯存根之后,生成的函數(shù)指針即成為函數(shù)的運行時實現(xiàn)。此代碼生成方法確保不會發(fā)生與運行時反射或元數(shù)據(jù)訪問相關(guān)的其他調(diào)用開銷。
在 SQL Server 和 CLR 之間快速轉(zhuǎn)換
編譯過程生成的函數(shù)指針可以在運行時通過本機(jī)代碼調(diào)用。對于標(biāo)量值用戶定義函數(shù),可基于每行調(diào)用此函數(shù)。為***程度地降低在 SQL Server 和 CLR 之間轉(zhuǎn)換的成本,包含任何托管調(diào)用的語句都具有一個標(biāo)識目標(biāo)應(yīng)用程序域的啟動步驟。該標(biāo)識步驟減少每行的轉(zhuǎn)換成本。
2.性能注意事項
以下內(nèi)容概述了 SQL Server 中特定于CLR集成性能的注意事項。有關(guān)更多詳細(xì)信息,請參閱 MSDN 網(wǎng)站上的“Using CLR Integration in SQL Server 2005”(在 SQL Server 2005 中使用 CLR 集成)。有關(guān)托管代碼性能的常規(guī)信息,請參閱 MSDN 網(wǎng)站上的“Improving .NET Application Performance and Scalability”(提高 .NET 應(yīng)用程序的性能和可擴(kuò)展性)。
3.用戶定義函數(shù)
相較于 Transact-SQL 用戶定義函數(shù),CLR 函數(shù)可以從更快的調(diào)用路徑中受益。此外,同 Transact-SQL 相比,托管代碼在過程代碼、計算和字符串操作方面具有決定性性能優(yōu)勢。需要大量計算和不執(zhí)行數(shù)據(jù)訪問的 CLR 函數(shù)采用托管代碼編寫時效果更好。但是與CLR集成性能相比,Transact-SQL 函數(shù)的確可以更有效地執(zhí)行數(shù)據(jù)訪問。
4.用戶定義聚合
托管代碼的性能大大優(yōu)于基于游標(biāo)的聚合。托管代碼的執(zhí)行速度通常稍慢于內(nèi)置 SQL Server 聚合函數(shù)的執(zhí)行速度。如果存在本機(jī)內(nèi)置聚合函數(shù),建議您使用該函數(shù)。對于所需聚合不受本機(jī)支持的情況,出于性能原因,請考慮使用 CLR 用戶定義聚合,而不是基于游標(biāo)的實現(xiàn)。
5.流式表值函數(shù)
應(yīng)用程序通常需要返回一個表作為調(diào)用函數(shù)的結(jié)果。示例包括從文件讀取表格格式數(shù)據(jù)作為導(dǎo)入操作的一部分,并將逗號分隔值轉(zhuǎn)換為關(guān)系表示形式。通常,您可以通過在調(diào)用方使用結(jié)果表之前具體化和填充此結(jié)果表來實現(xiàn)此目的。CLR 與 SQL Server 的集成引入了一種名為流式表值函數(shù) (STVF) 的新擴(kuò)展性機(jī)制。托管 STVF 的性能優(yōu)于可比擴(kuò)展存儲過程實現(xiàn)的性能。STVF 是返回 IEnumerable 接口的托管函數(shù)。IEnumerable 具有導(dǎo)航 STVF 返回的結(jié)果集的方法。當(dāng)調(diào)用 STVF 時,返回的 IEnumerable 直接連接到查詢計劃。查詢計劃在需要提取行時調(diào)用 IEnumerable 方法。使用此迭代模型,結(jié)果在***行生成之后即可使用,而不需要等到整個表填充完。還可以極大地減少調(diào)用該函數(shù)而占用的內(nèi)存。
6.數(shù)組與游標(biāo)
當(dāng) Transact-SQL 游標(biāo)必須遍歷更容易表示為數(shù)組的數(shù)據(jù)時,使用托管代碼可以顯著提高性能。
7.字符串?dāng)?shù)據(jù)
SQL Server 字符數(shù)據(jù)(如 varchar)在托管函數(shù)中可以是 SqlString 或 SqlChars 類型。SqlString 變量將整個值的實例創(chuàng)建到內(nèi)存中。SqlChars 變量提供可用于獲得更好性能和可擴(kuò)展性的流式接口,而無需將整個值的實例創(chuàng)建到內(nèi)存中。這對于大型對象 (LOB) 數(shù)據(jù)尤為重要。此外,還可以通過 SqlXml.CreateReader() 返回的流式接口訪問服務(wù)器 XML 數(shù)據(jù)。
8.CLR 與擴(kuò)展存儲過程
允許托管過程向客戶端回發(fā)結(jié)果集的 Microsoft.SqlServer.Server 應(yīng)用程序編程接口 (API) 的性能優(yōu)于擴(kuò)展存儲過程使用的開放式數(shù)據(jù)服務(wù) (ODS) API。此外,System.Data.SqlServer API 支持 xml、varchar(max)、nvarchar(max) 和 varbinary(max) 等 SQL Server 2005 中引入的數(shù)據(jù)類型,但是尚未將 ODS API 擴(kuò)展為支持新的數(shù)據(jù)類型。
通過托管代碼,SQL Server 管理對內(nèi)存、線程和同步等資源的使用。這是因為公開這些資源的托管 API 是針對 SQL Server 資源管理器實現(xiàn)的。相反,SQL Server 無法查看或控制擴(kuò)展存儲過程的資源使用情況。例如,如果擴(kuò)展存儲過程占用過多 CPU 或內(nèi)存資源,則無法通過 SQL Server 檢測或控制此種情況。但是,SQL Server 可以使用托管代碼檢測到給定線程已有很長一段時間未生成結(jié)果,并強(qiáng)制該任務(wù)生成以便安排其他工作。因此,使用托管代碼可以提高可擴(kuò)展性,并改善系統(tǒng)資源使用情況。托管代碼可能帶來維護(hù)執(zhí)行環(huán)境和執(zhí)行安全檢查所需的額外開銷。例如,當(dāng)在 SQL Server 內(nèi)運行并需要執(zhí)行從托管代碼到本機(jī)代碼的大量轉(zhuǎn)換時,可能會發(fā)生此種情況(因為在托管代碼和本機(jī)代碼之間來回轉(zhuǎn)換時,SQL Server 需要對特定于線程的設(shè)置進(jìn)行額外維護(hù))。因此,對于在托管代碼和本機(jī)代碼之間進(jìn)行頻繁轉(zhuǎn)換的情況,擴(kuò)展存儲過程的性能大大優(yōu)于在 SQL Server 內(nèi)運行的托管代碼的性能。
注意:
建議您不要開發(fā)新的擴(kuò)展存儲過程,因為已不推薦使用此功能。
9.用戶定義類型的本機(jī)序列化
用戶定義類型 (UDT) 是作為標(biāo)量類型系統(tǒng)的擴(kuò)展性機(jī)制設(shè)計的。SQL Server 實現(xiàn)稱為 Format.Native 的 UDT 序列化格式。在編譯期間,檢查該類型的結(jié)構(gòu)以便生成針對該特定類型定義自定義的 MSIL。本機(jī)序列化是針對 SQL Server 的默認(rèn)實現(xiàn)。用戶定義序列化調(diào)用由類型作者定義的方法以執(zhí)行序列化。應(yīng)盡可能使用 Format.Native 序列化以便獲取***性能。
10.可比 UDT 的規(guī)范化
關(guān)系操作(例如對 UDT 進(jìn)行排序和比較)是針對值的二進(jìn)制表示形式直接執(zhí)行的。通過在磁盤上存儲 UDT 狀態(tài)的規(guī)范化(二進(jìn)制排序)表示形式可以實現(xiàn)此目的。規(guī)范化具有兩個優(yōu)點:避免構(gòu)造類型實例和方法調(diào)用開銷,進(jìn)而極大地降低了比較操作的成本;為 UDT 創(chuàng)建二進(jìn)制域,支持構(gòu)造直方圖、索引以及該類型的值的直方圖。因此,規(guī)范化 UDT 的性能配置文件類似于未涉及方法調(diào)用的操作的本機(jī)內(nèi)置類型性能配置文件。
11.可擴(kuò)展內(nèi)存使用量
為了在 SQL Server 中很好地執(zhí)行和調(diào)整托管垃圾回收,請避免使用大型單一分配。大小大于 88 千字節(jié) (KB) 的分配將被放置到大對象堆,這將導(dǎo)致垃圾回收的性能和調(diào)整結(jié)果遠(yuǎn)不如多個較小分配的性能和調(diào)整結(jié)果。例如,如果需要分配一個大型多維數(shù)組,***分配一個交錯(分散)數(shù)組。
【編輯推薦】