首页/数据/SQL 速查/DECIMAL 精度与浮点误区
函数速查60 条

DECIMAL 精度与浮点误区

精确小数用 DECIMAL/NUMERIC:金额、数量、税率一律用定点类型;FLOAT/DOUBLE 是近似值,二进制表示会带来比较与累计误差。

SQL 速查数据更新于 2026-10-13

定点类型与浮点误区

精确小数用 DECIMAL(p, s)(PostgreSQL 里是 numeric):p 是总位数,s 是小数位数,金额、税率、库存数量这类要求精确的值一律用它。FLOAT 与 DOUBLE 是二进制近似类型,0.1 这类十进制小数根本无法精确表示,累加与等值比较都会出现偏差。类型要一次定对:整数部分位数不足会溢出,小数位数不足会被四舍五入,且中间计算还会按规则推导结果类型。ROUND 只改变显示精度,不改变底层存储。

基本信息

定点类型MySQL 用 DECIMAL(p,s),PostgreSQL 用 numeric(p,s)
参数含义p 是总位数(含小数位),s 是小数位数
近似类型FLOAT 单精度与 DOUBLE 双精度存放的是近似值
典型误差0.1 + 0.2 在浮点下不等于 0.3
等值比较浮点值直接比较可能永远不成立
使用建议金额、税率、数量、积分一律用定点类型

典型使用场景

  • 金额存储:订单金额、税额、余额
  • 税率与折扣计算:需要固定小数位与明确的舍入方式
  • 库存与数量:参与加减后必须精确
  • 对账场景:多笔累加后与账面完全一致
  • 积分与虚拟币:不允许出现小数漂移
  • 接口精度约定:与前后端约定保留几位小数

示例

示例
-- 建表时用定点类型
CREATE TABLE orders (
  amount      DECIMAL(12,2) NOT NULL DEFAULT 0.00,   # 最多 10 位整数、2 位小数
  tax_rate    DECIMAL(5,4)  NOT NULL DEFAULT 0.0000, # 如 0.0600
  qty         INT           NOT NULL DEFAULT 0
) ENGINE=InnoDB;

-- 计算:先算再按要求舍入
SELECT amount,
       amount * tax_rate                  AS tax_raw,
       ROUND(amount * tax_rate, 2)        AS tax,
       ROUND(amount * (1 + tax_rate), 2)  AS payable
FROM orders;

-- 浮点误差演示(仅说明问题,不要这样存金额)
SELECT 0.1 + 0.2;   -- 近似值,不精确等于 0.3

类型选择参考

类型特点适用
DECIMAL / numeric精确十进制,可指定位数金额、税率、数量
INT / BIGINT精确整数计数、积分、以分为单位的金额
FLOAT近似,单精度科学计算、允许误差的场景
DOUBLE近似,双精度统计估算、允许误差的场景
CHAR / VARCHAR文本绝不要用来存数字参与计算
另一种常见做法是用整数存最小货币单位(如以分为单位存金额),配合应用层换算,同样能避免浮点误差,且比较与索引都简单。
用 FLOAT 或 DOUBLE 存金额,累加几十万行后偏差肉眼可见,对账会出现无法解释的几分钱差额。
ROUND 的舍入规则在两库都是四舍五入到指定位数,但它只影响结果值的精度,不改变列的存储类型;需要固定小数位就靠列类型约束。

使用要点

  • 选类型时留够整数位:业务增长后金额位数会变多
  • 明确小数位数:税率用四位、金额用两位是常见约定
  • 乘法结果要显式舍入,避免下游拿到超长小数
  • 涉及金额的比较用定点类型或整数分单位,不用浮点
  • 报表里统一展示精度,避免同一指标在不同页面位数不同
  • 导出的浮点数据要带精度说明,下游解析时按约定处理

易错点

  • 用 FLOAT 或 DOUBLE 存金额,累加后出现精度偏差,对账差额无法解释
  • 用浮点做等值比较,条件永远不成立或误判相等
  • DECIMAL 位数定得太紧,业务增长后整数部分溢出报错
  • 中途参与计算的常量是浮点字面量,结果被隐式提升为近似值
  • 在应用层用浮点类型接收金额,数据库精度被最后一公里毁掉

数据来源与参考

  • MySQL 8.0 Reference Manual · Numeric Types
  • PostgreSQL Documentation · Numeric Types
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌