【问题标题】:Does Table-Valued Function (SQL) create table on each call? [performance]表值函数 (SQL) 是否在每次调用时创建表? [表现]
【发布时间】:2026-01-30 16:40:01
【问题描述】:

好吧,这听起来可能是个菜鸟问题,但 SQL 并不是我真正的强项,所以我在这里请求一些帮助。

我正在尝试实现一些东西,但我担心性能问题。

我要解决的问题是这样的:

我有一列有很多用逗号分隔的数据 "," 像这样:data1,data2,data3,data57

我需要的是遍历每条数据,用逗号分隔所有记录,然后然后用那条数据做一些事情,你明白了吗?

我找到了can actually help me的解决方案,但我担心系统性能,因为我可能需要使用不同的参数多次调用该函数

每次调用表值函数 (UDF) 时都会创建一个表,还是 sql 服务器将其保存为缓存? [也许我宁愿需要一个临时表?]

提前感谢您的帮助!


注意:数据不是我的,我应该按原样使用它,所以建议更改数据库是不可能的(但我知道这是最好的情况)。 一种 注意2:这个问题/问题的目的是将初始数据导入数据库,性能可能不是一个严重的问题,因为它不会运行很多次,但我还是想考虑这个问题,并且尽我所能!

【问题讨论】:

  • 是的。该函数将在tempdb 中创建一个条目并填充它,然后在每次调用时处理它。
  • 好吧...感谢您的评论!请写一个正确的答案,我很乐意接受它:)
  • 顺便说一下,如果您能提供更好的解决方案来解决这个问题,请成为我的客人,我将不胜感激:)
  • 等等,既然你在 SQL Server 2016 中工作,为什么不使用STRING_SPLIT
  • 稍有耐心(比如 SQL Server 2018?),您将使用 STRING_AGG 反过来。在此之前,您可以使用 FOR XML PATH('') 技巧将字符串连接回逗号分隔的字符串。

标签: sql user-defined-functions udf sql-server-2016 table-valued-parameters


【解决方案1】:

由多个语句组成的用户定义的表值函数,正如您发现的那样,将在tempdb 系统数据库中创建一个对象,填充它,然后在对象超出范围时将其处理掉.

如果您想在相同的参数上多次运行此操作,您可以考虑创建一个表变量并自己将结果缓存在其中。但是,如果您要在逗号分隔值的不同列表中调用它,则没有避免开销的好方法。 SQL Server 并不是真正为大量字符串操作而构建的。

通常,对于一次性作业,这种 tempdb 使用对性能的影响不会成为您主要关心的问题。当它成为数据库日常工作中的一种常见模式时,它更令人担忧。

如果可以的话,我建议尝试使用适当大小的数据子集来衡量解决方案的性能。

既然你说你在 SQL Server 2016 上,你可以使用新的 STRING_SPLIT 函数,比如

SELECT t.Column1, t.Column2, s.value
FROM table t
CROSS APPLY STRING_SPLIT(t.CsvColumn, ',') s

无需定义新功能即可让您更接近您想要的位置。请注意,您的数据库需要在 2016 兼容级别 (130) 下运行才能使用,仅在 SQL 2016 上运行是不够的(他们经常使用新功能执行此操作以避免向后兼容破坏更改的风险)。

【讨论】:

  • 感谢您的回答,我正在尝试运行该查询以检查结果,但到目前为止它没有工作,它显示“无效的对象名称'STRING_SPLIT'”。另外我必须更改擦除 s.value,因为 's' 不代表任何表格,也许这是一个错字,你的意思是 t ?谢谢!
  • 好的,所以我打算将 s 作为别名添加到 STRING_SPLIT 返回的表中;但听起来你没有那个。你能检查数据库的兼容性级别吗?它可能设置为 2014 (120) 或 2012 (110),这将使您无法使用 STRING_SPLIT,除非您可以更改它。
  • 我刚刚从谷歌注意到我需要运行这个命令:“ALTER DATABASE TestAzureDB SET COMPATIBILITY_LEVEL = 130”
  • 我将在我的本地数据库中对此进行测试,并让我的公司现在了解兼容性级别的这种依赖性以使其能够运行,如果他们无法运行,我将不得不找到另一个解决方案,无论如何我将对其进行测试并通知您,谢谢伙计!
  • @TiagoM 我不会放弃您提到的 UDF 作为一种可能的解决方案,它可能对您有用。寻找完美的解决方案很容易陷入困境,而这通常是不可用的。 :) 无论如何,祝你好运。