我正在使用SQL UDF来封装简单的报告/业务逻辑。我应该避免这个吗?

时间:2010-01-28 22:09:45

标签: sql sql-server user-defined-functions modularity

我正在SQL Server 2008中为一些报告构建一个新数据库,并且有许多与此数据相关的常见业务规则可用于不同类型的报告。目前,这些规则大多数都是在较大的程序程序中使用遗留语言进行组合,我正试图将其转移到SQL。我正在努力从这些数据中实现报告的灵活性,例如SAS中的一些报告,C#中的一些报告等。

我目前的方法是打破这些通用规则(通常是非常简单的逻辑)并将它们封装在单独的SQL UDF中。性能不是问题,我只想使用这些规则在一种报告“快照”中填充静态字段,然后可以用它来以任何方式进行报告。

我喜欢这种模块化的方法,只要了解每条规则正在做什么(以及维护规则本身),但我也开始有点害怕维护也可能成为一场噩梦。有些规则依赖于其他规则,但我无法真正摆脱这些 - 这些东西相互叠加......这就是我想要的......我想? ;)

在数据库中,这种模块化方法是否有更好的方法?我是在正确的轨道上,还是我在太多的应用程序开发思维中考虑这个问题?

5 个答案:

答案 0 :(得分:2)

在某些时候,UDF的广泛使用将开始导致性能问题,因为它们是针对结果集中的每一行执行的,并且来自优化器的逻辑模糊,使得难以使用索引(即我不太了解性能如何不能成为一个问题,但你最了解你的要求)。对于某些功能,它们很棒;但要谨慎使用它们。

答案 1 :(得分:2)

在数据库端保持逻辑几乎总是正确的做法。

正如您在问题中提到的,大多数业务规则涉及非常简单的逻辑,但通常会处理大量数据。

数据库引擎是实现该逻辑的正确选择,因为首先,它将数据I/O保持在最低限度,其次,数据库可以更有效地执行大多数数据转换。

前段时间我写了一篇非常主观的博客文章:

一面注意:UDF与存储过程不同。

UDF是一个由查询内部可调用的函数,因此它只能执行非常有限的可能操作子集。

你可以做更多的是存储过程。

<强>更新

在您给出的示例中,如更改计算“派生字段”的逻辑,计算字段的UDF是正常的。

但是(以防万一)性能将成为一个问题(相信我,这可能会更快一点),使用基于集合的操作转换数据可能比使用UDF更有效第

在这种情况下,您可能希望创建一个视图,一个存储过程或一个表值函数,返回一个结果集,该结果集将包含一个更有效的查询,而不是限制自己更新UDF s(这是记录基)。

一个例子:您的查询有类似“用户得分”的内容,您认为可以对其进行更改并将其包装到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

,这将为引擎提供更大的优化空间,同时仍保留结果集结构并将逻辑与表示分离。

答案 2 :(得分:1)

我会说你走在正确的轨道上 - 随着变得越来越复杂,并且将共享的,重复的逻辑片段封装到UDF中,sql程序可以迅速失控,这是解决这个问题的完全合适的解决方案。 / p>

我经常将sql过程中的逻辑封装到一个名为UDF的sql过程中,以提高可读性。

在UDF上查看this MSDN article - 也许它会为您提供更多关于其用途的想法?

如果您打算大量使用UDF,则需要注意各种性能注意事项 - 例如标量与表UDF的性能以及CLR UDF的可能优势。

答案 3 :(得分:1)

SQL是基于设置的,并且在应用模块化方法时本质上表现不佳 函数,存储过程和/或视图 - 它们都抽象了底层逻辑。当您使用两个(或更多)使用相同表的函数/等时,性能问题就会发挥作用。这意味着当一个表可以被使用时,两个查询就成了相同的表。

使用多种功能对我说,数据模型非常“灵活”。对我而言,这意味着可疑的数据类型和整体列/表定义。需要函数/ etc,因为数据库将允许存储任何内容,这意味着坏数据的可能性非常高。我宁愿把精力放在始终拥有良好/有效的数据上,而不是在事后对抗现有的坏数据。

数据库是包含此逻辑的地方。它比应用程序代码更快,最重要的是 - 集中化以最小化维护。

答案 4 :(得分:0)

如果您有兴趣构建一个用于报告的数据仓库,那么您将尝试将尽可能多的内容放入ETL的Transform部分,以便您的报告SQL由工具和用户都能够生成的简单语句组成。

SSIS是非常强大的ETL工具,它附带SQL服务器用于此类事情。