927

我学习函数和存储过程已经有一段时间了,但我不知道为什么以及何时应该使用函数或存储过程。它们对我来说看起来一样,也许是因为我对此有点新手。

有人能告诉我为什么吗?

4

21 回答 21

781

函数是计算值,不能对环境进行永久性更改SQL Server(即不允许INSERTUPDATE允许语句)。

如果函数SQL返回标量值,则可以在语句中内联使用,如果返回结果集,则可以加入函数。

评论中值得注意的一点,总结了答案。感谢@Sean K Anderson:

函数遵循计算机科学的定义,因为它们必须返回一个值,并且不能更改它们作为参数(参数)接收的数据。函数不允许改变任何东西,必须至少有一个参数,并且它们必须返回一个值。存储过程不必有参数,可以更改数据库对象,也不必返回值。

于 2009-07-24T19:42:14.013 回答
720

SP和UDF的区别如下:

存储过程 (SP) 功能(UDF - 用户定义)
SP 可以返回零、单个或多个值。 函数必须返回单个值(可以是标量或表)。
我们可以在 SP 中使用事务。 我们不能在 UDF 中使用事务。
SP 可以有输入/输出参数。 仅输入参数。
我们可以从 SP 调用函数。 我们不能从函数中调用 SP。
我们不能在 SELECT/WHERE/HAVING 语句中使用 SP。 我们可以在 SELECT/WHERE/HAVING 语句中使用 UDF。
我们可以使用 SP 中的 Try-Catch 块进行异常处理。 我们不能在 UDF 中使用 Try-Catch 块。
于 2012-10-15T17:00:55.163 回答
196

函数和存储过程有不同的用途。虽然这不是最好的类比,但函数可以从字面上视为您在任何编程语言中使用的任何其他函数,但存储过程更像是单个程序或批处理脚本。

函数通常有一个输出和可选的输入。然后可以将输出用作另一个函数(SQL Server 内置,如 DATEDIFF、LEN 等)的输入,或用作 SQL 查询的谓词 - 例如,SELECT a, b, dbo.MyFunction(c) FROM tableSELECT a, b, c FROM table WHERE a = dbo.MyFunc(c)

存储过程用于在事务中将 SQL 查询绑定在一起,并与外界交互。ADO.NET等框架不能直接调用函数,但是可以直接调用存储过程。

函数确实有一个隐患:它们可能被滥用并导致相当讨厌的性能问题:考虑这个查询:

SELECT * FROM dbo.MyTable WHERE col1 = dbo.MyFunction(col2)

其中 MyFunction 声明为:

CREATE FUNCTION MyFunction (@someValue INTEGER) RETURNS INTEGER
AS
BEGIN
   DECLARE @retval INTEGER

   SELECT localValue 
      FROM dbo.localToNationalMapTable
      WHERE nationalValue = @someValue

   RETURN @retval
END

这里发生的是函数 MyFunction 为表 MyTable 中的每一行调用。如果 MyTable 有 1000 行,那么这就是针对数据库的另外 1000 个即席查询。同样,如果在列规范中指定时调用该函数,则将为 SELECT 返回的每一行调用该函数。

所以你确实需要小心编写函数。如果您从函数中的表中执行 SELECT,您需要问自己是否可以使用父存储过程中的 JOIN 或其他一些 SQL 构造(例如 CASE ... WHEN ... ELSE ...结尾)。

于 2009-07-24T20:06:18.973 回答
67

存储过程和用户​​定义函数的区别:

  • Select 语句中不能使用存储过程。
  • 存储过程支持延迟名称解析。
  • 存储过程通常用于执行业务逻辑。
  • 存储过程可以返回任何数据类型。
  • 与用户定义的函数相比,存储过程可以接受更多数量的输入参数。存储过程最多可以有 21,000 个输入参数。
  • 存储过程可以执行动态 SQL。
  • 存储过程支持错误处理。
  • 非确定性函数可用于存储过程。

  • 用户定义的函数可以在 Select 语句中使用。
  • 用户定义的函数不支持延迟名称解析。
  • 用户定义的函数通常用于计算。
  • 用户定义的函数应该返回一个值。
  • 用户定义的函数不能返回图像。
  • 用户定义的函数接受的输入参数数量少于存储过程。UDF 最多可以有 1,023 个输入参数。
  • 临时表不能用于用户定义的函数。
  • 用户定义的函数不能执行动态 SQL。
  • 用户定义的函数不支持错误处理。 UDF 中不允许使用RAISEERROROR 。@@ERROR
  • 非确定性函数不能在 UDF 中使用。例如,GETDATE()不能在 UDF 中使用。
于 2013-05-02T09:52:10.927 回答
58

当你想计算并返回一个值用于其他 SQL 语句时,编写一个用户定义的函数;当您需要时编写存储过程是对一组可能很复杂的 SQL 语句进行分组。毕竟,这是两个完全不同的用例!

于 2009-07-24T19:42:36.743 回答
55
存储过程 功能(用户定义的功能)
过程可以返回 0、单个或多个值 函数只能返回单个值
程序可以有输入、输出参数 函数只能有输入参数
不能从函数调用过程 函数可以从过程中调用
过程允许在其中选择以及 DML 语句 函数中只允许选择语句
异常可以通过过程中的 try-catch 块来处理 Try-catch 块不能在函数中使用
能在手续上进行交易管理 我们不能在函数中进行事务管理
不能在 select 语句中使用过程 函数可以嵌入到 select 语句中
过程可以影响数据库的状态意味着它可以对数据库执行CRUD操作 函数不能影响数据库的状态意味着它不能对数据库执行CRUD操作
过程可以使用临时表 函数不能使用临时表
程序可以改变服务器环境参数 函数不能改变环境参数
当我们需要时可以使用过程,而不是对一组可能复杂的 SQL 语句进行分组 当我们想要计算并返回一个值以供其他 SQL 语句使用时,可以使用函数
于 2018-07-07T11:57:33.397 回答
28

基本区别

函数必须返回一个值,但在存储过程中它是可选的(过程可以返回零或 n 个值)。

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

函数需要一个输入参数,这是强制性的,但存储过程可能需要 o 到 n 个输入参数。

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

提前差价

过程允许在其中使用 SELECT 以及 DML(INSERT/UPDATE/DELETE) 语句,而函数只允许在其中使用 SELECT 语句。

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

存储过程不能在 WHERE/HAVING/SELECT 部分的任何地方的 SQL 语句中使用,而函数可以。

返回表的函数可以被视为另一个行集。这可以在与其他表的 JOIN 中使用。

内联函数可以作为带有参数的视图,并且可以用于 JOIN 和其他 Rowset 操作。

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

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

资源

于 2014-02-28T10:55:26.520 回答
21

用户定义函数是 sql server 程序员可用的重要工具。您可以像这样在 SQL 语句中内联使用它

SELECT a, lookupValue(b), c FROM customers 

lookupValueUDF在哪里。使用存储过程时,这种功能是不可能的。同时你不能在 UDF 中做某些事情。这里要记住的基本内容是 UDF:

  • 无法创建永久更改
  • 无法更改数据

存储过程可以做这些事情。

对我来说,UDF 的内联用法是 UDF 最重要的用法。

于 2009-07-24T20:04:21.737 回答
17

存储过程 用作脚本。它们为您运行一系列命令,您可以安排它们在特定时间运行。通常运行多个 DML 语句,如 INSERT、UPDATE、DELETE 等,甚至 SELECT。

函数 用作方法。你传给它一些东西,它会返回一个结果。应该小而快 - 即时完成。通常在 SELECT 语句中使用。

于 2015-03-13T19:55:56.157 回答
8

存储过程:

  • 就像 SQL Server 中的一个微型程序。
  • 可以像选择语句一样简单,也可以像从数据库中的多个表中添加、删除、更新和/或读取数据的长脚本一样复杂。
  • (可以实现循环和游标,它们都允许您处理较小的结果或对数据进行逐行操作。)
  • 应该调用 using EXECorEXECUTE语句。
  • 返回表变量,但我们不能使用OUT参数。
  • 支持交易。

功能:

  • 不能用于更新、删除或向数据库添加记录。
  • 只需返回单个值或表值。
  • 只能用于选择记录。但是,它可以很容易地从标准 SQL 中调用,例如:

    SELECT dbo.functionname('Parameter1')
    

    或者

    SELECT Name, dbo.Functionname('Parameter1') FROM sysObjects
    
  • 对于简单的可重用选择操作,函数可以简化代码。请注意在函数中使用JOIN子句。如果您的函数有一个JOIN子句,并且您从另一个返回多个结果的 select 语句中调用它,则该函数调用将JOIN 这些表一起用于结果集中返回的每一行。因此,尽管它们有助于简化某些逻辑,但如果使用不当,它们也可能成为性能瓶颈。

  • OUT使用参数返回值。
  • 不支持事务。
于 2014-04-29T11:56:17.300 回答
8

用户定义函数。

  1. 函数必须返回一个值。
  2. 只允许 Select 语句,不允许我们使用 DML 语句。
  3. 它将只允许输入参数,不支持输出参数。
  4. 它不允许我们使用 try-catch 块。
  5. 函数内不允许事务。
  6. 我们只能使用表变量,它不允许使用临时表。
  7. 不能从函数调用存储过程。
  8. 可以从 select 语句中调用函数。
  9. UDF 可以在连接子句中用作结果集。

存储过程

  1. 存储过程可能会或不会返回值。
  2. 可以有select语句以及插入、更新、删除等DML语句
  3. 它可以有输入和输出参数。
  4. 对于异常处理,我们可以使用 try catch 块。
  5. 可以在存储过程中使用事务。
  6. 可以在其中使用表变量和临时表。
  7. 存储过程可以调用函数。
  8. 不能从 Select/Where/Having 等语句中调用过程。Execute/Exec 语句可用于调用/执行存储过程。
  9. 不能在 Join 子句中使用过程
于 2019-07-29T14:58:22.800 回答
7

SQL Server 函数(如游标)旨在用作您的最后武器!它们确实存在性能问题,因此应尽可能避免使用表值函数。谈论性能就是谈论在中级硬件的服务器上托管的具有超过 1,000,000 条记录的表;否则您无需担心功能造成的性能损失。

  1. 永远不要使用函数将结果集返回给外部代码(如 ADO.Net)
  2. 尽可能使用视图/存储过程组合。您可以使用 DTA(数据库优化顾问)给您的建议(例如索引视图和统计信息)从未来的增长性能问题中恢复——有时!

如需进一步参考,请参阅:http ://databases.aspfaq.com/database/should-i-use-a-view-a-stored-procedure-or-a-user-defined-function.html

于 2009-12-09T20:27:49.080 回答
6

要决定何时使用以下几点可能会有所帮助-

  1. 存储过程不能返回一个表变量,而 as 函数可以做到这一点。

  2. 您可以使用存储过程来更改服务器环境参数,而使用您不能使用的功能。

干杯

于 2009-07-24T19:54:50.087 回答
4

从返回单个值的函数开始。好处是您可以将常用代码放入函数中,并将它们作为结果集中的列返回。

然后,您可以将函数用于城市的参数化列表。dbo.GetCitiesIn("NY") 返回一个可以用作连接的表。

这是一种组织代码的方式。只有通过反复试验和经验才能知道什么时候可以重用,什么时候浪费时间。

此外,函数在 SQL Server 中也是一个好主意。它们速度更快,并且可以非常强大。内联和直接选择。注意不要过度使用。

于 2013-09-16T20:28:10.657 回答
4

这是更喜欢函数而不是存储过程的实际原因。如果您有一个存储过程需要另一个存储过程的结果,则必须使用 insert-exec 语句。这意味着您必须创建一个临时表并使用一条exec语句将存储过程的结果插入到临时表中。很乱。这样做的一个问题是insert-execs 不能嵌套

如果您遇到调用其他存储过程的存储过程,您可能会遇到这种情况。如果嵌套存储过程只返回一个数据集,则可以将其替换为表值函数,您将不再收到此错误。

这是我们应该将业务逻辑排除在数据库之外的另一个原因

于 2016-05-31T17:57:26.397 回答
3

Mssql 存储过程与函数:

在此处输入图像描述

于 2020-06-16T21:57:16.790 回答
3

我意识到这是一个非常古老的问题,但我没有看到任何答案中提到的一个关键方面:内联查询计划。

函数可以...

  1. 标量:

    CREATE FUNCTION ... RETURNS scalar_type AS BEGIN ... END

  2. 多语句表值:

    CREATE FUNCTION ... RETURNS @r TABLE(...) AS BEGIN ... END

  3. 内联表值:

    CREATE FUNCTION ... RETURNS TABLE AS RETURN SELECT ...

第三种(内联表值)被查询优化器本质上视为(参数化)视图,这意味着从查询中引用函数类似于复制粘贴函数的 SQL 主体(实际上没有复制粘贴),导致获得以下好处:

  • 查询计划器可以像优化任何其他子查询一样优化内联函数的执行(例如,消除未使用的列、下推谓词、选择不同的 JOIN 策略等)。
  • 组合几个内联函数不需要在将第一个函数的结果提供给下一个函数之前将其具体化。

上述可能会导致潜在的显着性能节省,尤其是在组合多个级别的功能时。


注意:看起来 SQL Server 2019 也将引入某种形式的标量函数内联

于 2019-01-18T06:52:04.857 回答
2
  • 函数必须返回一个值,而不是存储过程。
  • Select 语句仅在 UDF 中接受,而 DML 语句不需要。
  • 存储过程接受任何语句以及 DML 语句。
  • UDF 只允许输入,不允许输出。
  • 存储过程允许输入和输出。
  • Catch 块不能在 UDF 中使用,但可以在存储过程中使用。
  • UDF 中的函数中不允许有事务,但在存储过程中是允许的。
  • 在 UDF 中只能使用表变量,而不能在临时表中使用。
  • 存储过程允许表变量和临时表。
  • UDF 不允许从函数调用存储过程,而存储过程允许调用函数。
  • UDF 用于连接子句,而存储过程不能用于连接子句。
  • 存储过程将始终允许归零。相反,UDF 具有必须返回到预定点的值。
于 2013-10-15T12:19:13.263 回答
1
  • 函数可以在选择语句中使用,而 as 过程不能。

  • 存储过程接受输入和输出参数,但函数只接受输入参数。

  • 函数不能像过程一样返回文本、ntext、图像和时间戳类型的值。

  • 函数可以在 create table 中用作用户定义的数据类型,但过程不能。

***例如:-创建table <tablename>(name varchar(10),salary getsal(name))

这里的getsal是一个用户定义的函数,它返回一个salary类型,当创建表时没有为salary类型分配存储空间,并且getsal函数也没有执行,但是当我们从这个表中获取一些值时,getsal函数get被执行并且返回类型作为结果集返回。

于 2012-07-21T19:33:57.043 回答
0

通常使用存储过程对性能更好。例如,在以前版本的 SQL Server 中,如果将函数置于 JOIN 条件下,基数估计为 1(SQL 2012 之前)和 100(SQL 2012 之后和 SQL 2017 之前),并且引擎可能会生成错误的执行计划。

此外,如果将其放在 WHERE 子句中,SQL 引擎可能会生成错误的执行计划。

在 SQL 2017 中,Microsoft 引入了称为交错执行的功能,以产生更准确的估计,但存储过程仍然是最佳解决方案。

有关更多详细信息,请参阅 Joe Sack 的以下文章 https://techcommunity.microsoft.com/t5/sql-server/introducing-interleaved-execution-for-multi-statement-table/ba-p/385417

于 2020-07-05T22:07:25.613 回答
-2

在 SQL Server 中,函数和存储过程是两种不同类型的实体。

函数:在 SQL Server 数据库中,函数用于执行一些动作,动作立即返回结果。函数有两种类型:

  1. 系统定义

  2. 用户自定义

存储过程:在 SQL Server 中,存储过程存储在服务器中,可以返回零值、单个值和多个值。存储过程有两种类型:

  1. 系统存储过程
  2. 用户定义程序
于 2015-12-17T07:19:06.543 回答