对Parallel Scalar UDF的支持是否合理?


10

相当有据可查的是,标量UDF强制执行总体串行计划。

并行运行功能

鉴于大量行进入必须计算UDF的管道中的某个点,为什么引擎不能只在处理器之间分配它们呢?如果UDF中没有状态,则顺序无关紧要。

有人声称UDF是黑匣子,必须使用游标。我可以看到,在两次迭代之间保持某种状态的情况下,用户游标无法在SP内并行化,但是看起来应该可以并行化。

解释引擎为何强制整个计划按顺序进行而不是仅由UDF计算阶段进行的加分。

对并行UDF的支持是否是要求的合理功能?


1
链接的可接受答案中指出,应该采取适当的措施将所有标量用户定义函数重写为单列内联表值函数。它们以与视图相同的方式扩展,因此已得到充分优化。有鉴于此,您的问题仍然值得吗?
Pieter Geerkens 2014年

1
是的,TVF解决方法成功。我问,因为避免使用这种自然构造似乎是错误的。期望新的SQL开发人员学习UDF内部知识似乎也不切实际。
crokusek

澄清评论。ITVF成功,但多语句TVF失败。
crokusek 2014年

Answers:


17

相当有据可查的是,UDF强制执行总体序列计划。

我不确定文件是否全部记录在案。

  • 标量T-SQL函数可防止计划中任何地方的并行性。
  • 标量CLR函数可以并行执行,只要它不访问数据库即可。
  • 多语句表值T-SQL函数在计划中强制使用可能在其他地方使用并行性的串行区域。
  • 内联表值T-SQL函数像视图一样扩展,因此没有直接作用。

请参阅强制执行并行执行计划和/或Craig Freedman的并行执行演示

有人声称UDF是黑盒,必须使用光标。

这些说法是不正确的。

解释引擎为何强制整个计划按顺序进行而不是仅由UDF计算阶段进行的加分。

我的理解是,当前的限制纯粹是某些实现细节的结果。没有根本原因无法使用并行性执行功能。

具体来说,T-SQL标量函数在单独的T-SQL上下文中执行,这使正确的操作,协调和关闭(尤其是在发生错误的情况下)显着复杂化。

同样,表变量通常确实支持并行读取(但不支持写入),但是由于实现特定的原因,表值函数公开的表变量不支持并行读取。恐怕您需要有人可以访问源代码(并且可以自由共享详细信息)来提供权威的答案。

对并行UDF的支持是否是要求的合理功能?

当然,如果您可以提出足够的理由。我自己的感觉是,所涉及的工作将是广泛的,所以你的提议必须满足一个非常高吧。例如,提供内联标量函数的相关(且更简单)的请求得到了很大的支持,但是多年来一直没有实现。


您可能想阅读Microsoft的论文:

...概述了Microsoft在SQL Server 2017之后的版本中解决T-SQL标量函数性能问题的方法。

Froid的目标是使开发人员能够使用UDF和过程的抽象,而不会影响性能。Froid通过一种新颖的技术来实现这一目标,只要有可能,它将命令式程序自动转换为等效的关系代数形式。Froid将命令式代码块建模为关系表达式,并使用Apply运算符将它们系统地组合为单个表达式,从而使查询优化器可以选择高效的面向集合的并行查询计划。

(强调我的)


内联标量T-SQL函数现在在SQL Server 2019中实现


11

正如Paul在其回答中正确提到的那样,没有根本的原因无法使用并行性执行标量UDF。但是,除了实现方面的挑战外,还有其他原因迫使它们必须串行化。保罗引用的Froid论文提供了更多有关此的信息。

引用本文(第2.3节):

当前,SQL Server在调用UDF的查询中不使用查询内并行性。可以设计一些方法来减轻这种限制,但是它们会带来其他挑战,例如为UDF的每次调用选择合适的并行度。

例如,考虑一个调用其他SQL查询的UDF,如图1所示。每个这样的查询本身都可能使用并行性,因此,优化器无法知道如何在它们之间共享线程,除非它查找了UDF并确定其中每个查询的并行度(可能从一个调用更改为另一个调用)。使用嵌套和递归的UDF,此问题变得更加难以管理。

如本文所述,Froid的方法不仅会导致并行计划,而且还会为使用UDF的查询带来更多好处。从本质上讲,它包含了您对UDF并行执行的请求。

更新: Froid现在作为SQL Server 2019预览功能提供。该功能称为“标量UDF内联”。此处有更多详细信息:https : //blogs.msdn.microsoft.com/sqlserverstorageengine/2018/11/07/introducing-scalar-udf-inlining/

[披露:我是Froid论文的合著者]


很好!如果我正确理解,它将在内部有效地将UDF自动转换为ITVF。我们做了几个(带有声明/如果/否则),并弄得一团糟。我们甚至有一个调试“列”。
crokusek

1
它实际上并没有将UDF转换为ITVF,但是您的直觉是正确的。对于复杂的UDF,在SQL查询级别手动执行此操作确实很麻烦。Froid在关系代数树上进行了这种转换,从而避免了混乱:)
Karthik

@Karthik,您可以看看dba.stackexchange.com/questions/202211/…。我真的很想知道Froid在上述案例中的表现如何
Roman Pekar

@罗马我已经评论了你的问题。
Karthik

1
谢谢@Karthik,感谢您在Froid纸上所做的工作,以及您(和小组)在改善标量UDF可用性方面所做的努力:-)
Solomon Rutzky
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.