从标量 UDF 引用表 - 绑定到模式名称?

Posted

技术标签:

【中文标题】从标量 UDF 引用表 - 绑定到模式名称?【英文标题】:Reference a table from a scalar UDF - tied to schema name? 【发布时间】:2014-11-19 15:35:16 【问题描述】:

由于我们系统的推出/架构,我想创建一个标量 UDF 以在存储过程中的 SELECT 语句中使用

由于我们的各种 DEV/TEST/LIVE 环境具有不同的架构名称,我希望将我的 UDF 命名为 dbo.MyFunctionName,但是,因为我的函数包含使用 SELECT 语句从数据库中获取值的逻辑表返回答案,这意味着我不能使用 dbo,但必须将它放在数据库的架构下(即:TEST)注意 - 这是对的,对吗?

SELECT 语句调用函数时,您必须提供由两部分组成的名称,因此我必须使用 TEST.MyFunctionName

SELECT Name, Age, TEST.MyFunctionName(PersonID) FROM People

有没有一种方法可以参数化模式名称,这样当我将它推出到不同的模式时,我不需要在每个模式下创建函数和/或修改它的调用方式?理想情况下,我正在寻找类似

SELECT Name, Age, SCHEMA_NAME().MyFunctionName(PersonID) FROM People

但如果可能,我不想使用动态 SQL

非常感谢

【问题讨论】:

将这样的标量函数放在选择列表中会导致糟糕的性能。一般来说,你应该尽量避免使用标量函数,因为几乎总是有更有效的方法来做同样的事情。内联表值函数 (iTVF) 是替换标量 udf 的最常用方法之一。 Sean,iTVF 是否只是创建一个返回表的函数,然后将其加入我的 SELECT 语句?我正在尝试优化一个系统,该系统几乎已经创建了一个包含所有值的临时表,无论 SELECT 语句返回 1、100 还是 1000 个结果。还是 iTVF 更有活力? 标量值函数会阻止优化器创建并行计划,并且对基数估计也有不良影响。简而言之:如果您将标量函数替换为内联表值函数,我从未见过执行得更快的查询,所以它当然值得一试。对于返回一个值的简单函数,请使用CROSS APPLY 感谢 Jeroen - 我的函数除了 SELECT 语句之外还有其他逻辑。我读过的所有关于 ITVF 的文章都显示 RETURN AS RETURN(SELECT...),我需要在返回之前做更多的逻辑。这种方法对我仍然有效吗? 不,内联 TVF 必须写为单个 SELECT 语句,没有过程逻辑。但是,通过适当使用 CTE (WITH x AS (...)),您会惊讶于可以将多少逻辑填充到单个 SELECT 中。不过,这已经偏离了轨道——如果您需要帮助将现有函数重写为 TVF,请提出一个新问题。 【参考方案1】:

你的问题其实是两个问题:

我的函数是否需要与其选择的表具有相同的架构?答案是dbo.MyFunction() 可以从test.MyTable 中选择就好了。但是,您可能会遇到所有权链接问题——不同的模式意味着用户必须存在明确的权限才能从表中进行选择。详情请见Books Online。 是否可以在不使用动态 SQL 的情况下调用具有参数化架构的函数?答案是。对象名称是静态的——尽管 SQL 确实具有延迟名称解析形式的“功能”,它允许您在存储过程中引用对象,即使它们不存在,但这仍然不允许您创建架构名称变量。

【讨论】:

感谢 Jeroen - 你是绝对正确的,并在第一点纠正我,因为我将能够创建 dbo 的功能。 (接受您的 cmets re:所有权链接)。【参考方案2】:

我会更高度建议将架构更改为不同的服务器(理想情况下 - 保持实例/数据库/模式名称相同),否则不同实例(不太理想,但保持数据库/模式名称相同),或者至少不同的数据库(更不理想,但保持模式名称相同)。仅从纯编码和测试的角度来看,您正在将测试与生产代码和数据混合在一起。这是一种容易犯错误和跨数据模式的方法。为什么要强制生产在开发中遇到性能问题?你甚至不能单独备份/恢复开发。即使这些不同的模式位于不同的数据库或服务器中,从 QA 的角度来看,您在“开发”中测试的代码不是正在部署到生产环境的代码。

但是,您可以通过使用不同的用户来实现这一点而无需太多技巧。每个用户都有一个默认架构。如果您有三个用户:DevUser、TestUser 和 LiveUser,每个用户都有各自的默认模式,那么在引用对象时您将使用模式名称。 SQL Server 将首先检查默认架构。这样,每个用户都会得到他们各自的对象。

【讨论】:

以上是关于从标量 UDF 引用表 - 绑定到模式名称?的主要内容,如果未能解决你的问题,请参考以下文章

雪花标量 UDF 返回 无法评估不支持的子查询类型

当另一个工作簿处于活动状态时,UDF 引用命名表错误

使用表、字段和模式名称查找引用的表名称

BigQuery 中使用引用另一个表的 UDF 的相关子查询错误

通过引用和标量变量传递 Perl 哈希

Excel UDF 在已关闭的工作簿中引用表以进行查找