抖音技术能力大揭密!钜惠大礼、深度体验,尽在火山引擎增长沙龙,就等你来! 立即报名>> 了解详情
写点什么

SQL Server 2019 修复函数内联 bug,速度提高 1000 倍

2019 年 1 月 06 日

SQL Server 2019修复函数内联bug,速度提高1000倍

与过去几十年出现的大多数数据库一样,SQL Server 允许开发人员通过创建函数来扩展数据库。但在即将发布的 SQL Server 2019 之前,SQL Server 在执行标量函数时,速度要慢 1000 倍。


与过去几十年出现的大多数数据库一样,SQL Server 允许开发人员通过创建函数来扩展数据库。但在即将发布的 SQL Server 2019 之前,SQL Server 对标量函数的支持存在很多问题。


在 SQL Server 中,返回单个值的函数被称为“标量 UDF”或“标量用户定义函数”。这些标量 UDF 由数据库自动归类为确定性或非确定性的。例如,非确定性函数用于读取当前时间或从表中获取数据。确定性函数始终为给定的参数集返回相同的值。理论上,数据库如果知道正在使用的是确定性 UDF,那么就可以针对这些函数进行优化。


遗憾的是,SQL Server 从未将标量 UDF 支持完全集成到执行计划生成器中。因此,它经常会做一些不必​​要的工作,例如会在每一行上执行确定性函数,但其实如果只针对每个唯一值执行一次函数会更快。


重复使用之前的值多少次以上才会带来实际的好处?这个很难说。除非数据是预先排序的,或者它知道可能的输入数量是有限的,否则缓存函数参数和结果的成本可能会超过收益。而这并不是标量 UDF 存在的唯一问题。


SQL Server 标量 UDF 的另一个问题是它们给并行化带来了阻碍。跨多个 CPU 分发复杂查询的能力是 SQL Server 的主要卖点。(很多开源替代品几乎没有并行支持或者只能依赖分布式数据库)。如果没有并行化,就很难证明 SQL Server 对得起它的价格。


说到价格,我们根本无法估计一个 SQL Server 标量函数究竟有多贵。所有的标量函数,不管是简单的还是复杂的,在执行计划中都会被赋予一个默认的成本。


标量 UDF 与调用它们的查询之间是单独进行解释的。根据微软的说法,对于每一行数据,都涉及到查询与函数之间的上下文切换。我们可以假设上下文切换的成本可能会超过函数本身的成本。


出于这些原因,很多开发人员和 DBA 建议不要在对性能要求较高的代码中使用标量函数,尽管将标量函数的内容粘贴到需要它的每个查询、视图和存储过程中会导致大量代码重复。于是,我们经常会听到诸如“除了视图之外的代码重用不适合数据库”这样的说法。


标量函数的性能损失不容小觑,例如这个简单的函数:


CREATE FUNCTION dbo.discount_price(@price DECIMAL(12,2), @discount DECIMAL(12,2))RETURNS DECIMAL (12,2) ASBEGIN    RETURN @price * (1 - @discount);END
复制代码


微软研究员 Karthik Ramachandra 表示,这个标量函数可能会导致一个通常只需要 1.6 秒的查询变成 29 分 11 秒那么久。虽然没有语义差异,速度却慢了 1000 倍。


解决方法是使用“内联表值函数”或“内联 TVF”代替标量函数。表值函数通常会返回一组行,但也可以将它们改写成只返回一行。这个时候,可以使用 CROSS APPLY 运算符模拟正常的标量函数调用。


SQL Server 2019 中的函数内联

从 SQL Server 2019 开始,可以内联用使用 T-SQL 编写的标量函数。这意味着它们可以被嵌入到查询中,并且不会有 UDF 那样的开销。在查看执行计划时,包含逻辑代码的查询与使用内联标量函数的查询之间是没有区别的。


这个新功能不仅限于简单的表达式。一些多语句 UDF 也可以被内联,甚至可以内联涉及从表中读取数据的非确定性 UDF。它还以推断出是否需要添加 JOIN 或 GROUP BY 运算符,以便将查询中的表与函数中的表组合在一起。


当然,并非所有函数都可以被内联。要进行内联,UDF 需要满足以下要求:


满足以下所有条件的标量 T-SQL UDF 可以被内联:


  • 使用以下构造编写的 UDF:

  • DECLARE、SET:变量声明和赋值。

  • SELECT:具有单/多变量赋值的 SQL 查询。

  • IF/ELSE:具有任意级别的嵌套分支。

  • RETURN:单个或多个返回语句。

  • UDF:嵌套/递归函数调用。

  • 其他:关系操作,如 EXISTS、ISNULL。

  • 不调用任何与时间相关的内部函数(例如 GETDATE())或具有副作用的函数(例如 NEWSEQUENTIALID())的 UFD。

  • 使用 EXECUTE AS CALLER 子句(如果未指定 EXECUTE AS 子句,则这个为默认行为)的 UDF。

  • 不引用表变量或表值参数的 UDF。

  • 调用了标量 UDF,但其 GROUP BY 子句中不引用标量 UDF 调用的查询。

  • 不是原生编译的 UDF。

  • 不是被用在计算列或检查约束定义中的 UDF。

  • 不引用用户定义类型的 UDF。

  • 没有添加任何签名的 UDF。

  • 不是用于分区的 UDF。


对于每个 T-SQL 标量 UDF,sys.sql_modules 视图中都有对应的 is_inlineable 属性,这个属性用于指示 UDF 是否可以内联。值为 1 表示它是可内联的,0 表示不可以内联。对于所有内联 TVF,这个属性的值均为 1。对于所有其他模块,该值为 0。


可以通过将数据库兼容级别设置为小于 150 或者将 TSQL_SCALAR_UDF_INLINING 的作用域配置设置为 OFF 来禁用 UDF 内联。


也可以通过 OPTION (USE HINT(‘DISABLE_TSQL_SCALAR_UDF_INLINING’))在给定查询上禁用内联。


你也可以在声明函数时使用 WITH INLINE = OFF 来表示永久禁用内联。


Froid 项目和未来的机会

如果没有 Froid 研究项目,可能就无法将该功能添加到 SQL Server。Froid 项目被描述为:


用于优化关系数据库命令式程序的可扩展框架。Froid 自动将整个用户定义函数(UDF)转换为关系代数表达式,并将它们嵌入到 SQL 查询中。这种形式可以进行基于成本的优化,并且可以生成有效的、面向集合的并行计划,而不是 UDF 那种低效、迭代、串行的执行过程。Froid 还为 UDF 带来了很多编译器优化,而不需要进行额外的实现。我们介绍了 Froid 的设计,并展示了我们的实验评估,它在实际工作负载上带来了多达数个数量级的性能改进。


目前只知道 Froid 框架支持 T-SQL,但论文中也提到了 C#、Java、Python 和 R 语言。由于 SQL Server 现在支持这四门语言中的三门,因此将函数内联扩展到其他语言会带来很大好处。


查看英文原文:https://www.infoq.com/news/2019/01/SQL-Server-Scalar-UDF-Inlining


2019 年 1 月 06 日 07:006802
用户头像

发布了 731 篇内容, 共 378.8 次阅读, 收获喜欢 1887 次。

关注

评论

发布
暂无评论
发现更多内容

Flutter 学习笔记(一) Text 组件

U+2647

flutter 四月日更

用APICloud开发仿微信聊天App制作经验分享

APICloud

小程序云开发 前端开发 web开发 APP开发 APICloud

架构实战业命题二学习总结

Vic

架构实战营

【架构实战营】第二模块作业

围绕工作的务实学习

架构实战营

上线半天下载量破100W!美团大佬的Java性能调优实战手册,超详细

Crud的程序员

Java 编程 架构

【架构实战营】第二模块总结

围绕工作的务实学习

架构实战营

四种软件架构概述

xcbeyond

Serverless 微服务架构 分布式架构 单体架构 4月日更

面向对象编程九诫

风翱

面向对象编程 4月日更

「前端初学者、硬件爱好者、编程自学者」微信小程序开发很简单!

智能物联实验室

前端 前端开发 前端进阶 硬件设计 硬件研发

如何避免团队里出现搭便车现象

石云升

团队建设 28天写作 职场经验 管理经验 4月日更

2021最新发布:Java面试突击大全 带你摸熟20+互联网公司面试考点

比伯

Java 编程 架构 程序人生 计算机

第二课作业

杰语

爬虫实例:爬取中国大学排名Top20

Bob

Python python 爬虫 四月日更

腾讯司晓:区块链如何在数字世界中重塑所有权?

CECBC区块链专委会

跨省通办,海淀在全国率先推出“区块链+”服务新模式

CECBC区块链专委会

推荐!看完全面掌握,最详细的 Docker 学习笔记总结(2021最新版)

民工哥

Docker 程序员 容器 DevOps 运维

微服务中台技术解析之sso登录实践

小江

Java 架构设计 后端开发 SSO

8421的数学含义

山@支

自学软件测试怎么学?(送思维导图+学习资源)

程序员阿沐

软件测试 性能测试 自动化测试 学习路线 测试开发

马丁量化策略系统搭建,量化交易软件开发

13823153121

【得物技术】得物前端性能监控实践

得物技术

前端 体验 监控 用户体验 实践

混沌工程缓存实战系列一Redis

心远

缓存 混沌工程

架构实战营模块二命题作业

Vic

架构实战营

lakin跟投社区APP开发|lakin跟投社区软件系统开发

开發I852946OIIO

系统开发

streamlit:算法工程师快速编写demo的利器

行者AI

算法

我把这个软件,推荐给了总监

yes

Service Mesh 从“趋势”走向“无聊”

阿里巴巴云原生

Java 运维 云原生 dubbo 中间件

分布式系统当中的CAP理论

五分钟学大数据

分布式 CAP理论 4月日更

跨链技术如何破解区块链的可扩展性难题?

CECBC区块链专委会

区块链

让孩子爱上阅读(一)

箭上有毒

读书笔记 4月日更

浪潮云说丨打造网络安全“铜墙铁壁”

浪潮云

云计算

Study Go: From Zero to Hero

Study Go: From Zero to Hero

SQL Server 2019修复函数内联bug,速度提高1000倍-InfoQ