【问题标题】:Functions vs Stored Procedures函数与存储过程
【发布时间】:2010-09-15 17:47:41
【问题描述】:

假设我必须实现一段 T-SQL 代码,该代码必须返回一个表作为结果。我可以实现一个表值函数或返回一组行的存储过程。我应该使用什么?

简而言之,我想知道的是:

函数和存储过程之间的主要区别是什么?在使用其中一种时我必须考虑哪些因素?

【问题讨论】:

标签: sql sql-server database function stored-procedures


【解决方案1】:

如果您可能希望将这段代码的结果与其他表结合起来,那么显然表值函数将允许您在单个 SELECT 语句中组合结果。

通常,有一个层次结构(视图

因此,请使用能够表达您想要的结果的最低限度的任何一个。

【讨论】:

    【解决方案2】:

    函数必须是确定性的,不能用于对数据库进行更改,而存储过程允许您进行插入和更新等操作。

    您应该限制函数的使用,因为它们会为大型复杂查询带来巨大的可伸缩性问题。它们成为查询优化器的“黑匣子”,您会发现使用函数和简单地将代码插入查询之间在性能上的巨大差异。

    但在非常特殊的情况下,它们对于表值回报绝对有用。

    如果您需要解析逗号分隔的列表,以模拟将数组传递给过程,函数可以为您将列表转换为表格。这是 Sql Server 2005 的常见做法,因为我们还不能将表传递给存储过程(我们可以使用 2008)。

    【讨论】:

    • 但是您可以将 XML 发送到存储过程:stackoverflow.com/questions/144550/…
    • 错了,大部分SQL server函数都是非确定性的,比如MS-SQL server中的getdate。只有 ODBC 函数是规范函数(=快得多 + 可索引)...但是您说得非常正确,出于性能原因,应该尽可能限制在查询中使用函数。
    【解决方案3】:

    From the docs:

    如果存储过程满足以下条件,则可以将其重写为表值函数:

    • 逻辑可以在单个 SELECT 语句中表达,但它是一个存储过程,而不是一个视图,只是因为需要参数。

    • 存储过程不执行更新操作,除了表变量。

    • 不需要动态的 EXECUTE 语句。

    • 存储过程返回一个结果集。

    • 存储过程的主要目的是构建要加载到临时表中的中间结果,然后在 SELECT 语句中对其进行查询。

    【讨论】:

      【解决方案4】:

      我将写一些存储过程和函数之间有趣的区别。

      • 我们可以在选择查询中使用函数,但不能使用存储的 选择查询中的过程。
      • 我们不能在 Functions 中使用非确定性函数,但我们可以 在存储过程中使用非确定性函数。 现在问题来了,什么是非确定性函数.. 答案是:-

        非确定性函数是在不同时间为相同输入值返回不同输出的函数,例如 getdate()。每次运行时它总是返回不同的值。

        例外:-

        sql server 2000 之前的早期版本不允许在用户定义的函数中使用 getdate() 函数,但 2005 及更高版本允许我们在用户定义的函数中使用 getdate() 函数。

        Newid() 是另一个非确定性函数的例子,但不能在用户定义的函数中使用,但我们可以在存储过程中使用。

      • 我们可以在存储的 过程,但我们不能在物理函数中使用 DML 语句 表或永久表。如果我们想在 我们可以通过表变量而不是永久表来执行函数。

      • 我们不能在函数中使用错误处理,但我们可以做错误 在存储过程中处理。

      【讨论】:

      • MySQL函数怎么支持DML操作?
      • @JoeyPinto。因为 myNONsql 不是 SQL 投诉。当然,它有附加功能,但没有基础功能。
      【解决方案5】:
      1. 过程可以返回零或 n 值,而函数可以返回 一个强制值。

      2. 过程可以有输入/输出参数,而函数只能有输入参数。

      3. Procedure 中允许 select 以及 DML 语句,而 function 中只允许 select 语句。

      4. 函数可以从过程中调用,而过程不能 从函数调用。

      5. 异常可以由过程中的try-catch块处理,而try-catch块不能在函数中使用。

      6. 我们可以在过程中进行事务管理,而不能在函数中进行。

      7. 过程不能在 select 语句中使用,而函数可以嵌入在 select 语句中。

      8. UDF(用户定义函数)可以在WHERE/HAVING/SELECT部分的任何位置的SQL语句中使用,而存储过程不能。

      9. 可以将返回表的 UDF 视为另一个行集。这可以在JOINs 中与其他表一起使用。

      10. 内联 UDF 可以视为采用参数的视图,并可用于JOINs 和其他行集操作。

      【讨论】:

        【解决方案6】:

        如果你有一个函数,你可以将它用作 SQL 语句的一部分,例如

        SELECT function_name(field1) FROM table
        

        这种方式不适用于存储过程。

        【讨论】:

        • 我认为他在谈论返回表值的函数。
        • 好吧,我说的是一般情况。但对于我的具体情况,我现在处于存储过程或表值函数之间。
        【解决方案7】:

        我用长时间运行的逻辑运行了一些测试,在表值函数和存储过程以及直接的 EXEC/SELECT 中运行相同的代码位(长 SELECT 语句),并且每个执行相同.

        在我看来,总是使用表值函数而不是存储过程来返回结果集,因为它使逻辑在随后加入它们的查询中更容易和可读,并且使您能够重用相同的逻辑。为了避免过多的性能损失,我经常使用“可选”参数(即您可以将 NULL 传递给它们)以使函数能够更快地返回结果集,例如:

        CREATE FUNCTION dbo.getSitePermissions(@RegionID int, @optPersonID int, optSiteID int)
        AS
        RETURN 
            SELECT DISTINCT SiteID, PersonID
            FROM dbo.SiteViewPermissions
            WHERE (@optPersonID IS NULL OR @optPersonID = PersonID)
            AND (@optSiteID IS NULL OR @optSiteID = SiteID)
            AND @RegionID = RegionID
        

        通过这种方式,您可以在许多不同的情况下使用此功能,并且不会对性能造成巨大影响。我相信这比事后过滤更有效:

        SELECT * FROM dbo.getSitePermissions(@RegionID) WHERE SiteID = 1
        

        我在几个函数中使用了这种技术,有时还有一长串这种类型的“可选”参数。

        【讨论】:

          【解决方案8】:

          当我返回的只是一个没有影响的表时,我个人使用表值函数。基本上,我将它们视为参数化视图。

          如果我需要返回多个记录集或者表中将更新值,我使用存储过程。

          我的 2 美分

          【讨论】:

            【解决方案9】:

            如上所述,函数更具可读性/可组合性/自记录性,但通常性能较差,如果您在诸如

            之类的连接中对它们感到厌烦,则性能可能会严重下降
            SELECT *
            FROM dbo.tvfVeryLargeResultset1(@myVar1) tvf1
            INNER JOIN dbo.tvfVeryLargeResultset1(@myVar2) tvf2
                ON (tvf1.JoinId = tvf2.JoinId)
            

            通常,您只需要接受 tvf 可以消除的冗余代码(以不可接受的性能成本为代价)。

            我还没有提到的另一点是,您不能在多语句 tvf 中使用数据库状态更改临时表。 与临时表功能最等效的机制是非状态变化,在内存表变量中,对于大型数据集,临时表可能比表变量性能更高。 (其他替代方法包括动态表和公用表值表达式,但在一定程度的复杂性下,这些不再是 IMO 的好选择。)

            【讨论】:

              【解决方案10】:

              我会对两者进行性能测试。 sp 方法或派生表可能比函数快得多,如果是这样,则应使用该方法。一般来说,我会避免使用函数,因为它们可能会消耗性能。

              【讨论】:

                【解决方案11】:

                这取决于:) 如果你想在另一个过程中使用表值结果,你最好使用表值函数。如果结果是针对客户的,那么存储过程通常是更好的选择。

                【讨论】:

                  【解决方案12】:

                  存储过程是预编译的查询,执行速度更快,并且可以从 sql 注入中保存。它们可以返回 0 或 N 个值。我们可以在存储过程中执行 DML 操作。我们可以在过程中使用函数,也可以在选择查询中使用函数。 函数用于返回函数中不可能的任何值和 DML 操作。 函数有标量和表值两种类型。标量函数返回单个值,用于返回表行的表值函数。

                  【讨论】:

                  • 这是一个非常古老的问题,有很多答案,其中许多(包括已接受的答案)都受到高度评价。在向此类主题添加另一个答案之前,您应该问自己,“所有这些现有答案缺少什么需要我写另一个答案?”
                  猜你喜欢
                  • 2011-05-14
                  • 2010-11-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-04-23
                  • 2016-04-15
                  • 1970-01-01
                  相关资源
                  最近更新 更多