Erik Darling Asked: 2017-10-01 08:40:04 +0800 CST2017-10-01 08:40:04 +0800 CST 2017-10-01 08:40:04 +0800 CST 有没有办法防止计算列中的标量 UDF 抑制并行性? 772 有关SQL Server中标量 UDF的危险的文章很多。随意搜索会返回大量结果。 不过,在某些地方,标量 UDF 是唯一的选择。 例如:在处理 XML 时:XQuery 不能用作计算列定义。Microsoft 记录的一种选择是使用标量 UDF将 XQuery 封装在标量 UDF 中,然后在计算列中使用它。 这有各种影响和一些解决方法。 查询表时逐行执行 强制对表的所有查询串行运行 您可以通过模式绑定函数来绕过逐行执行,并保留计算列或对其进行索引。即使没有引用标量 UDF,这些方法都不能阻止对表的查询的强制序列化。 有没有已知的方法可以做到这一点? sql-server functions 2 个回答 Voted Best Answer Paul White 2017-10-01T22:21:30+08:002017-10-01T22:21:30+08:00 是的,如果您: 正在运行 SQL Server 2014 或更高版本;和 能够在跟踪标志 176处于活动状态的情况下运行查询;和 计算列是PERSISTED 具体来说,至少需要以下版本: SQL Server 2016 SP1 的累积更新 2 SQL Server 2016 RTM 的累积更新 4 SQL Server 2014 SP2 的累积更新 6 但是为了避免这些修复中引入的错误(参考2014和2016 和 2017 ),请改为应用: SQL Server 2017 的累积更新 1 SQL Server 2016 SP1 的累积更新 5 SQL Server 2016 RTM 的累积更新 8 SQL Server 2014 SP2 的累积更新 8 跟踪标志作为启动–T选项是有效的,在全局和会话范围内使用DBCC TRACEON,以及使用OPTION (QUERYTRACEON)计划指南的每个查询。 跟踪标志 176 防止持久计算列扩展。 编译查询时执行的初始元数据加载会引入所有列,而不仅仅是那些直接引用的列。这使得所有计算列定义都可用于匹配,这通常是一件好事。 作为一个不幸的副作用,如果加载的(计算的)列之一使用标量用户定义函数,它的存在会禁用整个查询的并行性,即使计算的列实际上没有被使用。 跟踪标志 176 有助于解决此问题,如果列是持久的,则不加载定义(因为跳过了扩展)。这样,用户定义的标量函数就不会出现在编译查询树中,因此不会禁用并行性。 跟踪标志 176 的主要缺点(除了很少记录之外)是它还阻止查询表达式匹配到持久计算列:如果查询包含与持久计算列匹配的表达式,跟踪标志 176 将防止表达式被替换为对计算列的引用。 有关更多详细信息,请参阅我的 SQLPerformance.com 文章Properly Persisted Computed Columns。 由于问题提到了 XML,作为使用计算列和标量函数提升值的替代方法,您还可以查看使用 Selective XML Index,正如您在Selective XML Indexes: Not Bad At All中所写的那样。 Solomon Rutzky 2017-10-20T11:55:55+08:002017-10-20T11:55:55+08:00 除了@Paul 出色的Yes #1之外,实际上还有一个Yes #2 : 可以追溯到 SQL Server 2005, 不需要设置跟踪标志, 不要求计算列是,PERSISTED并且 (由于不需要跟踪标志 176),不会阻止查询表达式匹配到持久计算列 唯一的缺点(据我所知)是: 不适用于 Azure SQL 数据库(至少目前还不能,尽管它确实适用于 Amazon RDS SQL Server 以及 Linux 上的 SQL Server),并且 有点超出许多 DBA 的舒适区 这个选项是:SQLCLR 这是正确的。SQLCLR Scalar UDF 的一个很酷的方面是,如果它们不进行任何数据访问(无论是用户还是系统),那么它们就不会禁止并行性。这不仅仅是理论或营销。虽然我(目前)没有时间进行详细的撰写,但我已经测试并证明了这一点。 我使用了以下博客文章中的初始设置(希望 OP 不认为这是不可靠的来源?): 坏主意牛仔裤:多个索引提示 并进行了以下测试: 按原样运行初始查询 ─⇾ 并行性(如预期的那样) ([c2] * [c3])添加了定义为─⇾ Parallelism的非持久计算列(如预期的那样) 删除了该计算列并添加了一个非持久计算列,该列引用了SCHEMABINDING定义为RETURN (@First * @Second);─⇾ NO Parallelism(如预期)的 T-SQL 标量 UDF(使用创建) 删除了 T-SQL UDF 计算列并添加了一个非持久计算列,该列引用了IsDeterministic = true定义= false为return SqlInt32.Multiply(First, Second);─⇾ Parallelism (woo hoo!!) 因此,虽然 SQLCLR 并不适用于所有人,但对于那些非常适合的人/情况/环境来说,它肯定有其优势。而且,由于它与这个特定的问题有关——给出的例子是关于使用 XQuery 的——它肯定会为此工作(并且,根据具体所做的工作,它甚至可能会快一点?)。
是的,如果您:
PERSISTED
具体来说,至少需要以下版本:
但是为了避免这些修复中引入的错误(参考2014和2016 和 2017 ),请改为应用:
跟踪标志作为启动
–T
选项是有效的,在全局和会话范围内使用DBCC TRACEON
,以及使用OPTION (QUERYTRACEON)
计划指南的每个查询。跟踪标志 176 防止持久计算列扩展。
编译查询时执行的初始元数据加载会引入所有列,而不仅仅是那些直接引用的列。这使得所有计算列定义都可用于匹配,这通常是一件好事。
作为一个不幸的副作用,如果加载的(计算的)列之一使用标量用户定义函数,它的存在会禁用整个查询的并行性,即使计算的列实际上没有被使用。
跟踪标志 176 有助于解决此问题,如果列是持久的,则不加载定义(因为跳过了扩展)。这样,用户定义的标量函数就不会出现在编译查询树中,因此不会禁用并行性。
跟踪标志 176 的主要缺点(除了很少记录之外)是它还阻止查询表达式匹配到持久计算列:如果查询包含与持久计算列匹配的表达式,跟踪标志 176 将防止表达式被替换为对计算列的引用。
有关更多详细信息,请参阅我的 SQLPerformance.com 文章Properly Persisted Computed Columns。
由于问题提到了 XML,作为使用计算列和标量函数提升值的替代方法,您还可以查看使用 Selective XML Index,正如您在Selective XML Indexes: Not Bad At All中所写的那样。
除了@Paul 出色的Yes #1之外,实际上还有一个Yes #2 :
PERSISTED
并且唯一的缺点(据我所知)是:
这个选项是:SQLCLR
这是正确的。SQLCLR Scalar UDF 的一个很酷的方面是,如果它们不进行任何数据访问(无论是用户还是系统),那么它们就不会禁止并行性。这不仅仅是理论或营销。虽然我(目前)没有时间进行详细的撰写,但我已经测试并证明了这一点。
我使用了以下博客文章中的初始设置(希望 OP 不认为这是不可靠的来源?):
坏主意牛仔裤:多个索引提示
并进行了以下测试:
([c2] * [c3])
添加了定义为─⇾ Parallelism的非持久计算列(如预期的那样)SCHEMABINDING
定义为RETURN (@First * @Second);
─⇾ NO Parallelism(如预期)的 T-SQL 标量 UDF(使用创建)IsDeterministic = true
定义= false
为return SqlInt32.Multiply(First, Second);
─⇾ Parallelism (woo hoo!!)因此,虽然 SQLCLR 并不适用于所有人,但对于那些非常适合的人/情况/环境来说,它肯定有其优势。而且,由于它与这个特定的问题有关——给出的例子是关于使用 XQuery 的——它肯定会为此工作(并且,根据具体所做的工作,它甚至可能会快一点?)。