SQL 中函数调用的代价分析
发布时间 - 2026-01-25 00:00:00 点击率:次会,标量函数(如UPPER、CONVERT)在WHERE中逐行计算且阻断索引;ITVF可展开优化,MSTVF和UDF易致统计丢失、序列化执行;应避免列上函数,改用参数端转换或常量替换。
SQL 函数调用会拖慢查询吗?
会,但取决于函数类型和使用方式。标量函数(如 UPPER()、DATEADD())在 WHERE 或 SELECT 中对每行逐个计算,可能阻断索引下推、抑制并行执行,甚至让优化器放弃估算。而内联表值函数(ITVF)通常可展开为等价 SQL,代价接近原生查询;多语句表值函数(MSTVF)则像黑盒,常导致统计信息丢失和嵌套循环连接。
WHERE 子句里用 CONVERT() 或 CAST() 为什么查得慢?
这类显式转换常出现在“把字段转成字符串再模糊匹配”场景,例如:WHERE CAST(order_id AS VARCHAR) LIKE '123%'。问题在于:
- 字段被函数包裹后,无法走
order_id 列上的索引(即使该列是整型主键)
- SQL Server 无法对转换结果生成有效统计直方图,优化器容易低估/高估行数
- 如果
order_id 是聚集索引键,强制转换还会阻止范围扫描,退化为全索引扫描
更稳妥的做法是反向转换:把参数转为目标列类型,例如 WHERE order_id >= 12300 AND order_id (若业务允许前缀数字解析)。
GETDATE() 和 SYSDATETIME() 在 WHERE 中能用索引吗?
可以,但仅限于“列 >= 函数调用”这类单调递增表达式。例如:WHERE created_at >= GETDATE() - 1,优化器能将函数求值一次后转为常量,再配合 created_at 上的索引做范围查找。但以下写法会失效:
-
WHERE DATEDIFF(day, created_at, GETDATE()) = 0 —— 函数包裹列,索引失效
-
WHERE YEAR(created_at) = YEAR(GETDATE()) —— 同样破坏 sargability
注意:GETDATE() 是运行时标量函数,每次执行只算一次(非每行),但只要它让谓词不可 SARGable,索引就白搭。
自定义标量函数(UDF)为何比内置函数更危险?
SQL Server 2019 之前,UDF 默认被当作“黑盒”,优化器既不内联也不推导其行为,哪怕函数体只有一行 RETURN @x + 1。后果包括:
- 强制序列化执行(禁用并行)
- 每行调用一次,且无法复用中间结果(无缓存)
- 执行计划中显示为
Compute Scalar,但实际开销
常被严重低估
SQL Server 2019+ 启用 QUERY_OPTIMIZER_HOTFIXES 或数据库兼容级别 ≥ 150 后,部分简单 UDF 可自动内联——但必须满足:无副作用、无引用对象、无分支逻辑。否则仍退化为旧模式。
函数代价最隐蔽的地方不在 CPU,而在执行计划失真:你以为只是加了个 LEN(),结果优化器选了嵌套循环而非哈希连接,最后扫了千万行才出结果。别信“这个函数很简单”,先看执行计划里的 Actual Row Count 和 Operator Cost 分布。
CONVERT() 或 CAST() 为什么查得慢?
这类显式转换常出现在“把字段转成字符串再模糊匹配”场景,例如:WHERE CAST(order_id AS VARCHAR) LIKE '123%'。问题在于:
- 字段被函数包裹后,无法走
order_id列上的索引(即使该列是整型主键) - SQL Server 无法对转换结果生成有效统计直方图,优化器容易低估/高估行数
- 如果
order_id是聚集索引键,强制转换还会阻止范围扫描,退化为全索引扫描
WHERE order_id >= 12300 AND order_id (若业务允许前缀数字解析)。
GETDATE() 和 SYSDATETIME() 在 WHERE 中能用索引吗?
可以,但仅限于“列 >= 函数调用”这类单调递增表达式。例如:WHERE created_at >= GETDATE() - 1,优化器能将函数求值一次后转为常量,再配合 created_at 上的索引做范围查找。但以下写法会失效:
-
WHERE DATEDIFF(day, created_at, GETDATE()) = 0 —— 函数包裹列,索引失效
-
WHERE YEAR(created_at) = YEAR(GETDATE()) —— 同样破坏 sargability
注意:GETDATE() 是运行时标量函数,每次执行只算一次(非每行),但只要它让谓词不可 SARGable,索引就白搭。
自定义标量函数(UDF)为何比内置函数更危险?
SQL Server 2019 之前,UDF 默认被当作“黑盒”,优化器既不内联也不推导其行为,哪怕函数体只有一行 RETURN @x + 1。后果包括:
- 强制序列化执行(禁用并行)
- 每行调用一次,且无法复用中间结果(无缓存)
- 执行计划中显示为
Compute Scalar,但实际开销
常被严重低估
SQL Server 2019+ 启用 QUERY_OPTIMIZER_HOTFIXES 或数据库兼容级别 ≥ 150 后,部分简单 UDF 可自动内联——但必须满足:无副作用、无引用对象、无分支逻辑。否则仍退化为旧模式。
函数代价最隐蔽的地方不在 CPU,而在执行计划失真:你以为只是加了个 LEN(),结果优化器选了嵌套循环而非哈希连接,最后扫了千万行才出结果。别信“这个函数很简单”,先看执行计划里的 Actual Row Count 和 Operator Cost 分布。
# cos
# datediff
# 为什么
# sql
# 常量
# count
# select
# 整型
# 字符串
# 循环
# operator
# len
# 对象
# 数据库
# 这类
# 也不
# 序列化
# 子句
# 还会
# 出现在
# 而在
# 很简单
# 自定义
# 能将
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能
Laravel策略(Policy)如何控制权限_Laravel Gates与Policies实现用户授权
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
如何在万网主机上快速搭建网站?
js实现获取鼠标当前的位置
Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程
如何挑选最适合建站的高性能VPS主机?
Laravel如何处理表单验证?(Requests代码示例)
悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音
Win11怎么关闭专注助手 Win11关闭免打扰模式设置【操作】
大型企业网站制作流程,做网站需要注册公司吗?
详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七)
Bootstrap整体框架之JavaScript插件架构
Laravel如何实现文件上传和存储?(本地与S3配置)
Laravel怎么实现软删除SoftDeletes_Laravel模型回收站功能与数据恢复【步骤】
香港服务器部署网站为何提示未备案?
android nfc常用标签读取总结
如何在景安服务器上快速搭建个人网站?
Laravel怎么清理缓存_Laravel optimize clear命令详解
HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】
在centOS 7安装mysql 5.7的详细教程
教你用AI润色文章,让你的文字表达更专业
网站建设保证美观性,需要考虑的几点问题!
Laravel怎么实现模型属性的自动加密
Laravel如何创建自定义Facades?(详细步骤)
Laravel如何优化应用性能?(缓存和优化命令)
如何注册花生壳免费域名并搭建个人网站?
谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复
Laravel如何发送系统通知?(Notification渠道示例)
如何快速生成凡客建站的专业级图册?
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
如何在HTML表单中获取用户输入并结合JavaScript动态控制复利计算循环
Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案
如何在腾讯云服务器快速搭建个人网站?
香港服务器网站生成指南:免费资源整合与高速稳定配置方案
Laravel如何实现数据库事务?(DB Facade示例)
制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?
Python自动化办公教程_ExcelWordPDF批量处理案例
如何快速选择适合个人网站的云服务器配置?
深圳网站制作公司好吗,在深圳找工作哪个网站最好啊?
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
Laravel如何实现全文搜索功能?(Scout和Algolia示例)
如何在IIS中新建站点并配置端口与IP地址?
油猴 教程,油猴搜脚本为什么会网页无法显示?
Laravel怎么实现前端Toast弹窗提示_Laravel Session闪存数据Flash传递给前端【方法】
java ZXing生成二维码及条码实例分享
简单实现Android文件上传


