abs函数取绝对值,但null返回null、字符串转数字规则特殊、滥用会导致索引失效。

ABS 函数直接用,但负数和 NULL 要小心
ABS() 是 MySQL 内置函数,对数值取绝对值,用法简单:ABS(-123) 返回 123,ABS(0) 还是 0。但它对 NULL 的处理容易被忽略:只要参数是 NULL,结果一定是 NULL,不会报错也不会转成 0。比如 SELECT ABS(col) FROM t WHERE id = 999,如果 col 是 NULL,这一行就返回 NULL —— 看似“没数据”,其实是值本身为空。
常见错误现象:
- 在
ORDER BY ABS(x)中发现排序结果有“断层”,其实是某些x为NULL,被排到最前或最后(取决于 SQL mode) - 用
ABS(col) > 10做条件时,NULL行自动被过滤掉,误以为数据不全
字符串传给 ABS 会静默转成 0,不是你想要的“取绝对值”
MySQL 对类型不匹配比较宽容:把字符串传给 ABS(),它会尝试转换。但规则很朴素——从左开始读数字字符,遇到非数字就停。比如 ABS(' -42abc') 得 42(开头空格忽略,负号生效),而 ABS('abc-42') 得 0(第一个字符不是数字,直接转 0)。
使用场景中容易踩坑:
- 字段类型是
VARCHAR但存了数字,想统一取绝对值 → 必须先CAST(col AS SIGNED)或CONVERT(col, SIGNED),再套ABS() - 用户输入未校验,混入带单位的值如
'12.5kg'→ABS()返回12.5,但'kg12.5'就变成0 - 浮点字符串如
'3.14e2'会被识别为科学计数法,ABS()可处理,但精度可能丢失
在 WHERE 和 ORDER BY 里用 ABS,注意索引是否还能走
对字段直接套 ABS(col) 做条件或排序,基本等于放弃索引。MySQL 无法用 B+ 树索引快速定位 ABS(price) 这类表达式,因为函数改变了原始值分布。
性能影响明显:
-
WHERE ABS(score) > 50→ 全表扫描,哪怕score上有索引 -
ORDER BY ABS(created_at)→ 无法利用created_at索引,必须临时文件排序 - 替代方案:拆成两个范围查询,比如
WHERE score > 50 OR score ,这样能命中索引
浮点数用 ABS 要提防精度误差,尤其做等值判断
ABS() 本身不改变浮点精度,但会让原本因舍入产生的微小误差更难察觉。例如 0.1 + 0.2 在 MySQL 中是 0.30000000000000004,ABS(0.1 + 0.2 - 0.3) 结果仍是这个极小值,不是 0。
实际写法要注意:
- 避免
ABS(a - b) = 0判断浮点相等 → 改用ABS(a - b) -
DECIMAL字段不受此影响,优先在金额、精度敏感场景用DECIMAL而非FLOAT/DOUBLE - 计算中嵌套
ABS多次(如ABS(ABS(x) - y))不会累积误差,但可读性差,不如先赋值再算
ABS 的边界情况比看起来多:NULL、隐式转换、索引失效、浮点误差,每个都可能在某个查询里突然冒出来卡住你几小时。










