MySQL定点数类型详解 | 小册免费学

1,160 阅读4分钟

上一篇刚介绍了MySQL的浮点数类型,遗留了一个问题,即当数据需要精确存储的时候怎么办?MySQL既然是面向数据管理的,这点肯定是高瞻远瞩,早就帮我们解决啦,这就是小数的另一种数据类型,称之为定点数,即DECIMAL

有的朋友会说,哎不就是DECIMAL嘛,虽然不知道叫定点数,但我很常用的,这简单,有啥好介绍的。然而这里的设计可是有大文章的,不信,让我们一起探究下DECIMAL的前世今生吧。

定点数是什么?

维基百科上是这么说的:

定点数(英语:fixed-point number)是一种实数数据类型,要求小数点后位数固定,有时也要求小数点前位数固定。定点数与更复杂的浮点数相对。

有木有发现有点绕,其实简单来说就是用一种方式来精确表示小数,当然,如果插入的小数所需的长度大于设定的长度,是会报错的。

mysql> SHOW CREATE TABLE test_decimal\G
*************************** 1. row ***************************
       Table: test_decimal
Create Table: CREATE TABLE `test_decimal` (
  `d` decimal(3,1) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> INSERT INTO test_decimal VALUES (100.2356);
ERROR 1264 (22003): Out of range value for column 'd' at row 1

而如果是精度超过了,则会提示warning,在内部存储进行四舍五入。

mysql> INSERT INTO test_decimal VALUES (1.26);
Query OK, 1 row affected, 1 warning (0.01 sec)

mysql> select * from test_decimal;
+------+
| d    |
+------+
|  1.3 |
+------+
1 row in set (0.01 sec)

定点数的存储大小是固定的嘛?

要回答这个问题,需要先看MySQL中定点数的定义:

类型占用的存储空间(单位:字节)取值范围
DECIMAL(M, D)取决于MD取决于MD

哎,你发现这不是和浮点数很像嘛,如果不填MD,默认就是10 和 0,那为什么这里占用的存储空间不是固定的,而是取决于MD?难道是因为他有别的计算方式?是的,就是因为计算的方式变了,所以存储空间也不一样了。

那它如何表示来确保精度呢?因为在小数从十进制转换为二进制可能会丢失精度,所以就不转了,直接用小数点两边的两个整数搭配就可以了,牛逼吧!因为整数从十进制转换为二进制不会丢失精度,所以这就确保了这种方式不会丢失精度。

这里再提示下,MD的定义:

M 表示该小数最多需要的十进制有效个数。

D 表示该小数的小数点后的十进制数字个数。

那怎么存储呢?

我们用个例子来解释下。对于给定MD值的DECIMAL(M, D)类型,比如DECIMAL(16, 4)来说,小数点左边最多需要存储长度为12的十进制数,小数点右边最多需要存长度为4的十进制数。

1、划分组

从小数点位置出发,每个整数每隔9个十进制位划分为1组,效果就是这样的:

分组.png

可以看到当两边的大小不足9的时候,也会划分为一组。

2、计算组的存储空间

此时分组内还是十进制数,我们要把它转换成二进制数进行存储,组内数目不同,所需的空间也不同,对应关系如下表:

空间表.png

所以DECIMAL(16, 4)需要的存储空间为2 + 4 + 2 = 8 字节,同时转换完后最高位需要设置为1。而负数形式就先对数字转换之后对每个位取反即可,颇有补码的操作风范(唯一不同的就是取反后无需加1)!

从上边的叙述种我们可以知道,对于DECIMAL(M,D)类型来说,给定的M和D的值不同,所需的存储空间大小也不同。可以看到,与浮点数相比,定点数需要更多的空间来存储数据,所以如果不是在某些需要存储精确小数点的场景下,一般的小数用浮点数表示就足够了。

另外M的范围是1-65,D的范围是0-30,且D的值不能超过M。

——来自小册《MySQL 是怎样使用的:从零蛋开始学习 MySQL》

好啦,今天的内容就到这啦,你学会(fei)了吗?

本文正在参与「掘金小册免费学啦!」活动, 点击查看活动详情