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
子句、JOIN
或CROSS 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 中标量、表值和聚合函数之间的区别?的主要内容,如果未能解决你的问题,请参考以下文章