SQL Server 中标量、表值和聚合函数之间的区别?

Posted

技术标签:

【中文标题】SQL Server 中标量、表值和聚合函数之间的区别?【英文标题】:Difference between scalar, table-valued, and aggregate functions in SQL server? 【发布时间】:2016-04-17 17:13:09 【问题描述】:

SQL Server 中的标量值、表值和聚合函数有什么区别?从查询中调用它们是否需要不同的方法,还是我们以相同的方式调用它们?

【问题讨论】:

select get_turnover()select * from get_all_orders()有什么区别 【参考方案1】:

标量函数返回单个值。它甚至可能与您数据库中的表无关。

表值函数返回表中满足选择条件的行的指定列。

聚合值函数返回跨表行的计算——例如求和值。

【讨论】:

我明白了聚合和标量的意思。但是您能否为表值提供更多定义。并举一个简单的例子 @EhsanJeihani 表值函数或多或少是一个带参数的视图。有两种类型 - 内联和多语句。 ***.com/questions/2554333/… 典型的数据库查询会产生一组行。在一个简单的情况下,它们是从一个表中提取的。在您的查询中,您指定要检索表中的哪些列,并且您的 WHERE 子句指定给定表行需要满足的条件才能包含在结果行集中。【参考方案2】:

标量函数

标量函数(有时称为用户定义函数/UDF)返回单个值作为返回值,而不是作为结果集,并且可以在查询或SET 语句中的大多数地方使用,除了FROM 子句(可能还有其他地方?)。此外,可以通过EXEC 调用标量函数,就像存储过程一样,尽管使用此功能的场合并不多(有关此功能的更多详细信息,请参阅我在 DBA.StackExchange 上对以下问题的回答: Why scalar valued functions need execute permission rather than select?)。这些可以在 T-SQL 和 SQLCLR 中创建。

T-SQL (UDF):

在 SQL Server 2019 之前:这些标量函数通常是一个性能问题,因为它们通常针对返回(或扫描)的每一行运行并且始终禁止并行执行计划。 从 SQL Server 2019 开始:某些 T-SQL 标量 UDF 可以内联,也就是说,将它们的定义直接放入查询中,这样查询就不会调用 UDF(类似于iTVF 工作(见下文))。有一些限制可以防止 UDF 可内联(如果以前不是这样的话,现在是),并且由于多种因素,可以内联的 UDF 并不总是内联。可以在数据库、查询和单个 UDF 级别禁用此功能。有关这个非常酷的新功能的更多信息,请参阅:Scalar UDF Inlining(请务必查看“要求”部分)。

SQLCLR (UDF):这些标量函数通常也针对返回或扫描的每一行运行,但与 T-SQL UDF 相比有两个重要优势:

从 SQL Server 2012 开始,如果 UDF 不进行任何数据访问,并且如果它被标记为 IsDeterministic = true,则返回值可以常量折叠到执行计划中。在这种情况下,该函数不会按每一行运行。 SQLCLR 标量函数可以在不进行任何数据库访问的情况下以并行计划 (?) 工作。

表值函数

表值函数 (TVF) 返回结果集,可用于任何查询的FROM 子句、JOINCROSS APPLY / OUTER APPLY,但与简单视图不同,不能作为目标任何 DML 语句 (INSERT / UPDATE / DELETE)。这些也可以在 T-SQL 和 SQLCLR 中创建。

T-SQL MultiStatement (TVF):这些 TVF,顾名思义,可以有多个语句,类似于存储过程。他们将返回的任何结果都存储在表变量中并在最后返回;意思是,在函数完成处理之前什么都不返回。报告给查询优化器(影响执行计划)的估计返回行数取决于 SQL Server 的版本:

在 SQL Server 2014 之前:这些总是报告 1(是的,只有 1)行。 SQL Server 2014 和 2016:它们总是报告 100 行。 从 SQL Server 2017 开始:默认报告 100 行,但在某些情况下,由于新的 Interleaved Execution 功能,行数将相当准确(基于当前统计数据)。

T-SQL 内联 (iTVF): 这些 TVF 只能是单个语句,并且该语句是完整的查询,就像视图一样。事实上,内联 TVF 本质上是一个视图,它接受用于查询的输入参数。它们也不缓存自己的查询计划,因为它们的定义被放置在使用它们的查询中(与此处描述的其他对象不同),因此它们可以比其他类型的 TVF (?) 优化得更好。这些 TVF 执行得非常好,如果可以在单个查询中处理逻辑,则它们是首选。

SQLCLR (TVF):这些 TVF 与 T-SQL MultiStatement TVF 相似,因为它们在之前将整个结果集构建在内存中(即使是交换/页面文件)在最后释放所有这些。他们将返回的估计行数,报告给查询优化器(这会影响执行计划)总是 1000 行。鉴于固定行数远非理想,请支持我的请求以允许指定行数:Allow TVFs (T-SQL and SQLCLR) to provide user-defined row estimates to query optimizer

SQLCLR 流 (sTVF): 这些 TVF 允许像常规 SQLCLR TVF 一样复杂的 C#/VB.NET 代码,但特殊之处在于它们将每一行返回给调用查询它们被生成(?)。此模型允许调用查询在发送第一个查询后立即开始处理结果,因此查询无需等待函数的整个过程完成即可看到任何结果。而且它需要更少的内存,因为在过程完成之前结果不会存储在内存中。他们将返回的估计行数,报告给查询优化器(这会影响执行计划)总是 1000 行。鉴于固定行数远非理想,请支持我的请求以允许指定行数:Allow TVFs (T-SQL and SQLCLR) to provide user-defined row estimates to query optimizer

聚合函数

用户定义的聚合 (UDA) 是类似于 SUM()COUNT()MIN()MAX() 等的聚合,通常需要 GROUP BY 子句。这些只能在 SQLCLR 中创建,并且该功能是在 SQL Server 2005 中引入的。此外,从 SQL Server 2008 开始,UDA 得到了增强,以允许多个输入参数 (?)。一个特殊的缺陷是不知道组内的行排序,因此在 SAFE 程序集中创建运行总计(如果可以保证排序会相对容易)是不可能的。


另请参阅:

CREATE FUNCTION(MSDN 文档) CREATE AGGREGATE(MSDN 文档) CLR Table-Valued Function Example with Full Streaming (STVF / TVF)(我写的文章)

【讨论】:

【参考方案3】:

标量函数

返回单个值。这就像在其他编程语言中使用T-SQL 语法编写函数一样。

表值函数

与上面的有点不同。返回一个表值。在此函数的主体中,您编写一个将返回确切表的查询。 例如:

CREATE FUNCTION <function name>(parameter datatype)

RETURN table

AS

RETURN

(

-- *write your query here* ---

)

注意这里没有BEGIN & END 语句。

聚合函数

包括与GROUP 子句一起使用的内置函数。例如:SUM(),MAX(),MIN(),AVG(),COUNT() 是聚合函数。

【讨论】:

【参考方案4】:

聚合函数和标量函数都返回单个值,但标量函数基于单个输入 参数运行,而聚合函数基于单个输入运行一组值(集合或列名)。标量函数的示例有字符串函数、ISNULL、ISNUMERIC,聚合函数的示例有 AVG、MAX 等,您可以在 Microsoft 网站的Aggregate Functions 部分找到。

无论是否存在任何输入参数,表值函数都会返回一个表。通过将它们用作常规物理表来执行此功能,例如:SELECT * FROM fnGetMulEmployee()

以下链接对于理解差异非常有用:https://www.dotnettricks.com/learn/sqlserver/different-types-of-sql-server-functions

【讨论】:

以上是关于SQL Server 中标量、表值和聚合函数之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章

也来谈谈SQL SERVER 自定义函数~

SQL Server 中系统视图sysobjects中type字段的说明

sql server表值函数和视图如何一起使用

SQL Server:表值函数与存储过程

SQL Server 表值函数和异常组合性能

SQL Server:表值函数不适用于子查询