2010-02-25 77 views
2

MSDN docscreate function爲什麼SQL-Server UDF如此有限?

User-defined functions cannot be used to perform actions that modify the database state.

我的問題很簡單 - 爲什麼

是的,修改數據的UDF可能具有潛在的不需要的副作用。
是的,如果一個UDF被調用幾千次,那麼會有開銷。

但這就是設計和測試的重點 - 確保在部署之前解決這些問題。那麼爲什麼DB廠商堅持要對開發人員施加這些人爲限制?什麼是語言結構的重點,基本上只能用作select語句的包裝?

這個問題的原因如下:我正在寫一個函數來爲某個唯一的整數ID返回一個GUID。如果已經爲該ID分配了一個GUID,我只需返回它;否則我想要生成一個新的GUID,將它存儲到一個表中,並返回新生成的GUID。 (是的,這聽起來很囉嗦,可能很瘋狂,但是當你將數據發送給另一個開發公司時,他們認爲他們的設計是上帝傳下來的,不能改進,只是微笑點頭,做他們想問的事)。

我知道我可以使用帶輸出參數的存儲過程來獲得相同的結果,但是爲了保存存儲過程的結果,我必須聲明一個新變量。不僅如此,我還必須將我的簡單select轉換爲插入臨時表的while循環,併爲該循環的每次迭代調用sproc。

+0

如果你需要一些東西來修改數據庫狀態 - 爲什麼不直接使用一個存儲過程,而不是? UDF的目的是做一個快速計算,查找或某物並返回一個值 - 這是他們的目標。他們做得很好。 – 2010-02-25 08:28:29

+0

因爲我想做一些類似'my_udf(my_variable)from my_table',其中my_udf選擇或創建它返回的值(正如我的文章中所解釋的)。使用sproc實現相同的結果會使代碼大10倍。 – 2010-02-25 09:37:34

回答

2

通常最好將可用工具視爲頻譜,從視圖到UDF,再到存儲過程。在一端(視圖)你有很多限制,但這意味着優化器實際上可以「看透」代碼並做出明智的選擇。在另一端(存儲過程),你有很大的靈活性,但是因爲你有這樣的自由,你失去了一些能力(例如,因爲你可以從一個存儲過程返回多個結果集,你失去了「編寫」它作爲更大查詢的一部分)。

UDF位於中間位置 - 比視圖中可以做得更多(例如多條語句),但是沒有存儲過程那麼靈活。通過放棄這種自由,它允許將輸出組合爲更大的查詢的一部分。通過沒有副作用,例如,您可以保證UDF的行順序無關緊要。如果您可能有副作用,優化程序可能不得不提供排序保證。

0

我理解你的問題,我認爲,但是從您的評論採取這樣的:

我想這樣做select my_udf(my_variable) from my_table,其中my_udf要麼選擇或創建它返回

所以值你想要一個select(可能)修改數據。你能自己看看這句話嗎?告訴我那句話完全沒問題? - 我當然不能。

讀你的東西,你真正需要做的描述:

我寫一個函數返回一個 GUID一定唯一的整數ID。 如果已經爲 分配了一個GUID,那麼我只需返回它;否則 我要生成一個新的GUID,商店 即到表中,並返回 新生成的GUID。

我知道我可以使用存儲過程 與輸出參數 達到同樣的效果,但後來我 有一個新的變量聲明只是爲了 保持存儲過程的結果。不僅 ,我必須將我的簡單 select轉換爲while循環,該循環將 插入臨時表中,並且針對該循環的每次迭代調用 sproc。

從它聽起來像你有一次處理許多行的最後一句話,所以怎麼樣一個INSERT是插入對於還沒有他們這些ID的GUID,後跟一個SELECT返回所有(現在)存在的GUID?

0

有時候如果你無法實現你想出了一個解決方案,它可能是一個跡象,你的解決方案不是最優的。

使用這樣

INSERT INTO IntGuids(IntValue, GuidValue) 
SELECT MyIntValues.IntValue, NEWID() 
FROM MyIntValues 
LEFT OUTER JOIN IntGuids ON MyIntValues.IntValue = IntGuids.IntValue 
WHERE IntGuids.IntValue IS NULL 

一個語句創建你需要有1個語句中的所有的GUID。不需要爲每個值選擇+ INSERT。