2010-01-28 17 views
7

我在SQL Server 2008中爲某些報告構建了一個新的數據庫,並且涉及到這些數據的許多常見業務規則進入了不同類型的報告。目前,這些規則大部分都是以較大的程序性程序結合在一起,這是一種傳統語言,我試圖將其轉移到SQL。我打算靈活地實現這些數據的報告,比如SAS中的一些報告,C#中的一些報告等。我正在使用SQL UDF來封裝簡單的報告/業務邏輯。我應該避免這一點?

我現在的做法是打破這些常見規則(通常非常簡單的邏輯)並將它們封裝在單個SQL UDF。性能不是問題,我只是想用這些規則來填充靜態字段中的某種報告「快照」,然後用它來以任何你想要的方式進行報告。

就理解每條規則正在做什麼(以及維護規則本身)而言,我喜歡這種模塊化方法,但我也開始擔心維護也可能成爲一場噩夢。有些規則依賴於其他規則,但我無法真正擺脫這種情況 - 這些東西彼此相互依存......這就是我想要的......我認爲呢? ;)

是否有數據庫中的這種模塊化方法一些更好的辦法?我是走在正確的軌道上,還是我在過多的應用程序開發思維中想到這一點?

+0

謝謝大家!看起來這種方法應該是OK :)同樣,性能不是問題,因爲它們僅在每個ETL /快照實例中使用一次。因此,填充這些函數輸出到的字段可能需要一兩分鐘或三天的時間,但在此之後,有人會始終只對表進行查詢,而不會使用查詢中的函數。那麼,至少他們不應該使用它們! – chucknelson 2010-01-28 23:44:37

回答

1

SQL是基於設置的,並且在應用模塊化方法時固有地表現不佳。
函數,存儲過程和/或視圖 - 它們都抽象了底層的邏輯。當您使用兩個(或更多)功能/等使用同一個表時,性能問題就會起作用。這意味着當可以使用一個表時,兩個查詢是相同的表。

多功能的使用對我說數據模型是非常「靈活」的。對我而言,這意味着可疑的數據類型和總體列/表定義。需要函數/等,因爲數據庫將允許存儲任何內容,這意味着不良數據的可能性非常高。我寧願將精力放在始終擁有良好/有效的數據上,而不是在事後處理現有的不良數據。

數據庫是包含這個邏輯的地方。它比應用程序代碼更快,最重要的是 - 集中化以最小化維護。

+0

我同意 - 我得到的基礎數據非常廣泛。我基本上將我的「快照」過程當作ETL步驟來處理,並使用這些UDF填充任何想要使用數據進行報告的人(或其他任何人)非常有用的字段。 – chucknelson 2010-01-28 22:34:14

+0

@ kucknelson:我明白 - 我目前的工作讓我履行類似的職責。 – 2010-01-28 22:39:46

2

在某些時候,廣泛使用UDF會導致性能問題,因爲它們會針對結果集中的每一行執行,並且會優化優化器中的邏輯,從而導致很難使用索引(即,我不太瞭解性能不成問題,但你最瞭解你的要求)。對於某些功能它們很棒;但謹慎地使用它們。

+0

我完全同意這一點,但我只是在使用這些特定「快照」來填充靜態字段時使用這些字段,而這些字段是有人爲了任何報告目的而查詢的。否則,我肯定會將這個邏輯轉移到報告層(並且爭取標準的報告實現),或者努力將事物轉換爲表值函數。儘管感謝您的反饋! – chucknelson 2010-01-28 22:21:18

+0

並非所有的UDF每行都執行一次,而內聯的UDF則被優化器壓扁。標量UDF確實很慢 – 2010-01-28 22:49:47

+0

表UDF不會爲每行執行? – JeffO 2010-01-29 03:46:48

1

我會說,你是在正確的軌道上 - SQL過程能夠迅速失控的越來越複雜和封裝共享,重複的邏輯塊放入UDF的是解決這個一個完全合適的解決方案。

我經常去儘可能遠離那個只在一個過程中使用到一個名爲良好UDF以提高可讀性一個SQL過程封裝邏輯。

對UDF的看看this MSDN article - 也許它會給你他們使用的一些更多的想法?

如果您打算大量使用UDF,您需要了解各種性能方面的考慮因素,比如標量vs表UDF的性能以及CLR UDF的可能優勢。

0

如果您在構建數據倉庫進行報告時感興趣,您可以嘗試儘可能多地將其放入ETL的Transform部分,以便您的報告SQL由工具和用戶都能夠生成的簡單語句組成。

SSIS是非常有能力的ETL工具自帶的SQL服務器這樣的事情。

+0

目前這是一個非常小的範圍,但我同意,我很樂意爲此使用一些適當的報告工具/流程。現在我試圖建立一些可維護,容易閱讀/理解的未來世代;) – chucknelson 2010-01-28 22:35:59

2

保持數據庫端的邏輯幾乎總是正確的。

正如你在你的問題中提到,大多數業務規則涉及很簡單的邏輯,但它通常以大量的數據交易。

數據庫引擎是實現該邏輯的正確方法,因爲它首先使數據保持最小,其次,數據庫更有效地執行大多數數據轉換。

前一段時間我寫了一個非常主觀的博客中對這個話題:

一個側面說明:一UDF是不一樣的存儲過程。

A UDF是一個由查詢內部可調用的函數設計的函數,因此它只能執行一個非常有限的可能操作子集。

你可以做更多的是存儲過程。

更新:

在你給了,比如改變計算「派生出來的字段」邏輯的例子中,計算領域是OK的UDF

但是(爲了以防萬一)當性能會成爲一個問題(並相信我,這可能會更快,人們可能會認爲),使用基於集合的操作來轉換數據可能會比使用UDF s更有效。

在這種情況下,您可能希望創建一個視圖,存儲過程或表值函數返回一個結果集,其中將包含寧可把自己侷限於更新UDF個更高效的查詢(這是基於記錄的) 。

一個例子:查詢有類似的東西,你覺得會隨時更改,並將其包裝成一個UDF

SELECT user_id, fn_getUserScore(user_id) 
FROM users 

最初「用戶評分」,這僅僅是在表中的平坦區域:

CREATE FUNCTION fn_getUserScore(@user_id INT) RETURNS INT 
AS 
BEGIN 
     DECLARE @ret INT 
     SELECT user_score 
     INTO @ret 
     FROM users 
     WHERE user_id = @user_id 
     RETURN @ret 
END 

,然後你決定使用來自其它表中的數據是計算:

CREATE FUNCTION fn_getUserScore(@user_id INT) RETURNS INT 
AS 
BEGIN 
     DECLARE @ret INT 
     SELECT SUM(vote) 
     INTO @ret 
     FROM user_votes 
     WHERE user_id = @user_id 
     RETURN @ret 
END 

這將譴責引擎在這兩種情況下使用效率最低的NESTED LOOPS算法。

但是,如果你創建的視圖,並改寫了基礎查詢是這樣的:

SELECT user_id, user_score 
FROM users 

SELECT user_id, SUM(vote) AS user_score 
FROM users u 
LEFT JOIN 
     user_votes uv 
ON uv.user_id = u.user_id 

,這將給引擎優化更廣泛的空間,同時仍保持結果集的結構和表現分離的邏輯。

+1

+1保持邏輯數據庫端(雖然許多人會強烈反對!) – davek 2010-01-28 22:19:55

+0

不知道我是否在尋找效率不僅僅是將這些規則與實施報告的選擇分開 - 我只希望人們能夠查看數據並且像「啊哈哈,有派生字段X,我想要過濾'N ''或類似的東西:)如果基於某些反饋的派生字段X的邏輯更改,只需更新一個或兩個UDF並更新該字段。這是我的願景,無論如何;) – chucknelson 2010-01-28 22:25:04

+0

'@ chucknelson':我希望我有人能夠看到數據中的「衍生領域」作爲我的客戶:) – Quassnoi 2010-01-28 22:27:21

相關問題