使用 Inline 表值函数封装 SQL 代码的性能

Posted

技术标签:

【中文标题】使用 Inline 表值函数封装 SQL 代码的性能【英文标题】:Performance using Inline table valued function to encapsulate SQL code 【发布时间】:2017-06-15 20:50:27 【问题描述】:

问题是:内联表值函数(ITVF)可以用来封装和重用代码吗?或者这会导致性能问题吗?

我正在研究内联表值函数,这导致我进行了以下讨论: When would you use a table-valued function?

讨论中的一个答案指出,内联表值函数“允许优化器处理这些函数与它们封装的对象没有区别,从而为您提供最佳性能(假设您的索引和统计信息是理想的)。”

我最初的问题是我试图将不同的数据源重新格式化为标准格式,然后合并它们。我测试了联合 6 种不同的 ITVF 与在一个查询中执行联合和转换。执行计划是相同的。

由于我的背景是 oop,我更愿意将查询拆分为更小的函数,但在我承诺在未来的项目中这样做之前,我想知道使用过多的 ITVF 是否最终会导致性能问题。

【问题讨论】:

不要陷入一个非常常见的误解,即添加“RETURNS TABLE”会使您的函数内联。它必须只有一个语句。如果您有变量或多行代码,那么性能将会非常糟糕……甚至比标量函数还要糟糕。 @SeanLange 什么算作单个语句?联合、交叉应用和子查询是否被视为一个或多个语句? 这将是一个单一的声明。如果您必须放置开始/结束块,则您没有内联函数。如果您的函数定义是“...AS RETURN...”,那么您的状态就很好。 :) 【参考方案1】:

可以使用内联表值函数 (ITVF) 来封装和重用代码吗?

是的。并且它们在这方面优于多语句 TVF,因为对于多语句 TVF,封装会阻止查询优化器将谓词推入 TVF 逻辑,并阻止它准确估计返回的行数。

或者这会导致性能问题吗?

简短的回答,通常不会。

更长的答案:

有 4 种方法可以封装和重用查询逻辑(整个查询,而不仅仅是标量表达式)。

    观看次数 内联表值函数 多语句表值函数 临时表 表变量

视图和内联 TVF 本身不会降低性能,但它们会增加查询优化的复杂性。

如果优化器未能始终如一地找到您可能需要干预的低成本计划。一种常见的方法是强制假脱机(即实现)中间结果,例如用多语句 TVF 替换内联 TVF,或提前将结果假脱机到临时表。

假脱机降低了封装查询的复杂性,但代价是在更大查询的上下文中运行时可能优化封装查询。

在假脱机结果时,临时表通常是最好的,因为 SQL Server 它们可以具有索引和统计信息,使 SQL Server 能够准确评估将使用中间结果的计划的成本。

【讨论】:

【参考方案2】:

ITVF 非常适合封装查询逻辑以供重复使用。我有十几个财务报告,它们都查询同一组表以获取大致相同的信息,并且通过创建一个提供该数据的函数,我可以确定我的所有报告都是从同一个数据体中提取的相同的过滤器和转换等。

话虽如此,您也可以轻松地创建视图而不是 ITVF,但 ITVF 还提供了一种根据发送的参数过滤或以其他方式转换数据的方法。例如,我的财务功能可以接受一个地区名称作为可选输入参数,仅返回该地区的数据。通过以这种方式使用 ITVF,优化器可以随着时间的推移根据传入的参数优化查询计划,这有助于而不是阻碍性能。

我建议不要在六个不同的 ITVF 上进行联合,而是将所有表合并到一个 ITVF:这样,如果表架构或报告需求发生变化,您就只有一个地方可以进行更新。

【讨论】:

以上是关于使用 Inline 表值函数封装 SQL 代码的性能的主要内容,如果未能解决你的问题,请参考以下文章

sql2005中 表值函数是啥

sql2005中 表值函数是啥

SQL SERVER函数之深入表值函数的处理分析

表值函数从 2012 年迁移到 sql 2017 后性能下降

等效于 Amazon Redshift 中的 T-SQL 表值构造函数?

将 T-SQL 表值函数字符串拆分为 C#