2013-01-15 35 views
2

在SQL Server中,我有一個基於CLR集成的表值函數GetArchiveImages。我稱之爲這樣的事情:使用CLR集成表函數進行高效交叉應用

SELECT ... 
FROM Items 
CROSS APPLY GetArchiveImages(Items.ID) AS archiveimages 
WHERE ... 

問題是每個單獨的函數調用都會有開銷。

如果它可以一次連接到整個表格,開銷會很小,但由於每行調用一次,所以開銷會隨着行數而變化。

我不使用存儲過程,因爲存儲過程返回的表不能與任何東西連接(據我所知)。

有沒有一種有效的方式來連接表與散裝的存儲過程或函數的結果,而不是逐行連接?

+0

也許'WITH'會適合您的需求。它會根據您選擇的select語句創建一個臨時表。 [這是一些信息](http://msdn.microsoft.com/en-us/library/ms175972.aspx)。那會是你想要的嗎? – Tikkes

+0

我對Common Table Expressions很熟悉,我不明白它們在這種情況下會如何。 –

回答

2

由於GetArchiveImages的結果取決於Items.ID,SQL Server必須調用每個項目的函數,否則您不會得到正確的結果。

SQL Server可以「分手」的唯一功能是T-SQL內嵌表值函數。因此,如果您可以將您的CLR重寫爲ITVF,您將獲得更好的性能。

根據我的經驗,調用CLR函數的大意並不那麼大。查詢中的其他地方出現問題的可能性更大。例如,SQL Server不知道該函數將返回多少行,只是假定它將是一個(用於每個調用)。這可能會導致優化過程中在其他地方做出錯誤的決策。


UPDATE:

SQL Server不允許保持一個CLR類中的靜態非恆定的數據。有很多方法可以欺騙系統,例如通過創建一個靜態的最終集合對象(你可以添加和刪除一個靜態集合中的項目),但是,我會建議反對,因爲穩定性的原因。

在你的情況下創建一個緩存表是可以通過某種(數據庫或文件系統)觸發器或按計劃自動刷新的。您可以不用調用該函數,而只需加入該表。

+0

這不是SQL Server的開銷,它是CLR函數的初始化,它每次調用時都會在文件系統中讀取幾個文件,但如果我可以調用per-查詢而不是每行。 –

+0

查看我剛添加的更新 –

+0

我想我必須接受沒有直接的方法來做到這一點,而且我不能在SQL Server的約束範圍內直接做我想做的事情。這將需要我想一個更有創意的解決方案。 –

1

如果GetArchiveImages()功能並不需要在多個查詢中使用,或類似的查詢外,至少不使用時,可以切換的這種外部和內部方面:在SQLCLR TVF做主要SELECT fields FROM [Items] WHERE ...。並將其製作成TVF流媒體。

將所需的基本結構:

  1. 定義類型的SqlDataRecord的變量是所有你想從[項目]加人返回領域的當前GetArchiveImages()函數返回。

  2. 閱讀「在文件系統中的幾個文件」(從@Sebastian MEINE的回答第一個評論拍攝)

  3. 打開使用"Trusted_Connection = true; Enlist = false;"作爲ConnectionString的一個SqlConnection的。

  4. 執行主要的SELECT fields FROM [Items] {optional WHERE}。如果可以在此處縮小某些行的範圍,請填寫WHERE。您甚至可以將值傳遞給該函數以傳遞給WHERE子句。

  5. 循環遍歷SqlDataRecord

    1. 填寫SqlDataRecord變量此行
    2. 獲取當前GetArchiveImages()功能是越來越基於[Items].[ItemID]
    3. 呼叫相關的項目yield return;
  6. 關閉SqlConnection

  7. 處置SqlDataReader,SqlCommandSqlConnection

  8. 關閉在步驟2中打開的任何文件(如果它們不能在流程中提前關閉)。