MySQL数据库中的浮点类型和高精度类型有什么区别?为什么不推荐使用浮点类型?

本文主要是介绍MySQL数据库中的浮点类型和高精度类型有什么区别?为什么不推荐使用浮点类型?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在软件开发中,作为后端,无可避免的需要熟练使用 MySQL 数据库进行数据存储和读取。对于信息系统而言,数据库的的地位不言而喻。那作为软件开发工程师,在使用 MySQL 过程中,又有哪些需要注意的呢?我们从实际开发来一点点的介绍。

本篇文章,我们先来了解一下关于数据库数字类型的一些内容。我们在做表设计的时候,数字类型是常见的数据类型,用于存储数字相关的信息(整数型、浮点型、高精度型)。但是在不同的业务场景中,错误的使用数字类型,也会给系统带来很大的风险。

一、数字类型

1、整数类型

MySQL 数据库支持 SQL 标准支持的整型类型:INT、SMALLINT。此外,MySQL 数据库也支持诸如 TINYINT、MEDIUMINT 和 BIGINT 整型类型。我们来看一下各整型所占用的存储空间及取值范围:

类型占用空间最小值-最大值(signed)最小值-最大值(unsigned)
TINYINT1-128~1270~255
SMALLINT2-32768~327680~65535
MEDIUMINT3-8388608~83886070~16777215
INT4-2147483648~21474836470~4294967295
BIGINT8-9223372036854775808~92233720368547758070~18446744073709551615

在整型数字类型中,有 signed 和 unsigned 的属性,表示的是整型的取值范围。默认是 signed。我们在设计时,建议不要刻意去用 unsigned 属性,因为在做数据分析时,SQL 可能会返回不是理想的结果。

2、浮点类型和高精度类型

MySQL 的数字类型中,除了上面说的整数类型,还有浮点型和高精度型。

MySQL 之前的版本中存在浮点类型 Float 和 Double,但这些类型因为不是高精度,也不是 SQL 标准的类型,所以在真实的生产环境中不推荐使用,否则在计算时,由于精度类型问题,会导致最终的计算结果出错。

更重要的是,在 MySQL8.0.17 版本开始,如果我们建表继续使用 FLOAT 和 DOUBLE,则会抛出警告:

Specifying number of digits for floating point data types is deprecated and will be removed in a future release

数字类型中的高精度 DECIMAL 类型可以使用,在设置字段为 DECIMAL 类型时,需要指定精度和标度。例如:

count DECIMAL(6,4)

其中,6 是精度(精度表示保存值的主要位数),4 是标度(标度表示小数点后面保存的位数)。通常在表结构设计中,类型 DECIMAL 可以用来表示用户的工程款项、账户的余额等精确到小数点后 4 位的业务。

然而,在海量并发的互联网业务中使用,金额字段的设计并不推荐使用 DECIMAL 类型,而更推荐使用 INT 整型类型。

二、表结构设计实战

1、整型与主键自增设计

在真实业务场景中,整型类型最常见的就是在业务中用来表示某件物品的数量。例如销售数量,或电商中的库存数量、购买次数等。在业务中,整型类型的另一个常见且重要的使用用法是作为表的主键,即用来唯一标识一行数据。

整型结合属性 auto_increment,可以实现自增功能,但在表结构设计时用自增做主键,特别要注意以下两点,若不注意,可能会对业务造成灾难性的打击:

  • 用 BIGINT 做主键,而不是 INT;

  • 自增值并不持久化,可能会有回溯现象(MySQL 8.0 版本前)。

从上述的类型对比中可以发现,INT 的最大范围在 42 亿级别,在互联网应有中,很容易就达到这个量级。比如一些日志表、浏览记录表等,每天 1000w 的数据增量,420 天后就达到了 INT 上限。

因此,用自增型做主键,应该使用 BIGINT,而不是 INT

另外,MySQL8.0 以前的版本,自增不持久化,自增值可能会存在回溯问题

我们以以下实例来看:

mysql> SELECT * FROM t;+---+| a |+---+| 1 || 2 || 3 |+---+3 rows in set (0.01 sec)mysql> DELETE FROM t WHERE a = 3;Query OK, 1 row affected (0.02 sec)mysql> SHOW CREATE TABLE t\G*************************** 1. row ***************************Table: tCreate Table: CREATE TABLE `t` (`a` int NOT NULL AUTO_INCREMENT,PRIMARY KEY (`a`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci1 row in set (0.00 sec

从上述代码可以看出,在删除自增为 3 的记录后,下一个自增依然为 4,这里没有问题,自增不会回溯。但如果此时数据库发生重启,那数据库启动后,表 t 的自增起始值会再次变为 3,这就是自增值发生回溯。

mysql> SHOW CREATE TABLE t\G*************************** 1. row ***************************Table: tCreate Table: CREATE TABLE `t` (`a` int NOT NULL AUTO_INCREMENT,PRIMARY KEY (`a`)) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci1 row in set (0.00 s

如果想解决这个问题,有以下两个做法:

  • 1、升级 MySQL 到 8.0 版本,让每个表的自增值持久化。

  • 2、如无法升级版本,则不推荐在核心业务表使用自增数据类型做主键。

其实在海量的互联网架构设计中,为了后续分布式架构更好的扩展,一般是不使用整型来做主键的,更为推荐的是使用字符串类型

2、资金字段设计

在用户余额、基金账户余额、数字钱包、零钱等的业务设计中,由于字段都是资金字段,通常技术人员习惯使用 DECIMAL 类型作为字段的选型,因为这样可以精确到分,如:DECIMAL(6,2)。

CREATE TABLE User (userId BIGINT AUTO_INCREMENT,money DECIMAL(8,2) NOT NULL,......)

在海量互联网业务的设计标准中,并不推荐用 DECIMAL 类型,而是更推荐将 DECIMAL 转化为 整型类型。也就是说,资金类型更推荐使用用分单位存储,而不是用元单位存储。如 1 元在数据库中用整型类型 100 存储。

金额字段的取值范围如果用 DECIMAL 表示的,如何定义长度呢?因为类型 DECIMAL 是个变长字段,若要定义金额字段,则定义为 DECIMAL(8,2) 是远远不够的。这样只能表示存储最大值为 999999.99,百万级的资金存储。

用户的金额至少要存储百亿的字段,而统计局的 GDP 金额字段则可能达到百万亿级别。用类型 DECIMAL 定义,不好统一。

另外重要的是,类型 DECIMAL 是通过二进制实现的一种编码方式,计算效率远不如整型来的高效。因此,推荐使用 BIG INT 来存储金额相关的字段

字段存储时采用分存储,即便这样 BIG INT 也能存储千兆级别的金额。这里,1 兆 = 1 万亿。

文章将持续更新,欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发

这篇关于MySQL数据库中的浮点类型和高精度类型有什么区别?为什么不推荐使用浮点类型?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/978112

相关文章

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

Qt QCustomPlot库简介(最新推荐)

《QtQCustomPlot库简介(最新推荐)》QCustomPlot是一款基于Qt的高性能C++绘图库,专为二维数据可视化设计,它具有轻量级、实时处理百万级数据和多图层支持等特点,适用于科学计算、... 目录核心特性概览核心组件解析1.绘图核心 (QCustomPlot类)2.数据容器 (QCPDataC

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1