Contents
  1. 1. int tinyint与bigint的比较
  2. 2. float和decimal

int tinyint与bigint的比较

它们都是(精确)数据类型,但是占用字节数和表达的范围不同

Type Storage Minimum Value Maximum Value
(Bytes) (Signed/Unsigned) (Signed/Unsigned)
TINYINT 1 -128 127
0 255
SMALLINT 2 -32768 32767
0 65535
MEDIUMINT 3 -8388608 8388607
0 16777215
INT 4 -2147483648 2147483647
0 4294967295
BIGINT 8 -9223372036854775808 9223372036854775807
0 18446744073709551615
遇到比较多的是tinyint和bigint,tinyint一般用于存放status,type这种数值小的数据,不够用时可能会用smallint。bigint一般用于自增主键. 为了避免数据库被过度设计,布尔、枚举类型也采用tinyint。

还有一点也是经常被提到的关于 int(M) 中M的理解,int型数据无论是int(4)还是int(11),都已经占用了 4 bytes 存储空间,M表示的只是显示宽度(display width, max value 255),并不是定义int的长度。

float和decimal

MYSQL使用DECIMAL类型去存储对精度要求比较高的数值,比如金额,也叫定点数,decimal在mysql内存是以字符串二进制存储的。声明DECIMAL(M,D),M是数字最大位数(精度precision),范围1-65;D是小数点右侧数字个数(标度scale),范围0-30,但不得超过M。

比如DECIMAL(18,9),整数部分和小数部分各9位,所以各占4字节,共8bytes
再比如DECIMAL(20,6),整数14位,需要4字节存9位,还需3字节存5位;小数6位,需3字节。共10bytes
(感谢 consatan 在评论区提出文中错误)

比如定义DECIMAL(7,3)

  • 能存的数值范围是 -9999.999 ~ 9999.999,占用4个字节
  • 123.12 -> 123.120,因为小数点后未满3位,补0
  • 123.1245 -> 123.125,小数点只留3位,多余的自动四舍五入截断
  • 12345.12 -> 保存失败,因为小数点未满3位,补0变成12345.120,超过了7位。严格模式下报错,非严格模式存成9999.999

MySQL使用FLOATDOUBLE来表示近似数值类型,这是因为十进制0.1在电脑里用二进制是无法精确表示的,只能尽可能的接近

单精度浮点数float占4字节,float标准语法允许通过FLOAT(M)的形式指定精度,但是这个精度值M只是决定存储大小: 0-23与默认不指定效果相同,24-53就变成双精度的DOUBLE了。

float还有非MySQL自己实现的非标准语法FLOAT(M,D),代表最多存储M个数字长度,其中小数点后数字个数为D。效果与 DECIMAL(M,D)很相似。

double 和 float 的区别是double精度高,有效数字16位(float精度7位)。但double消耗内存是float的两倍,占8字节,double的运算速度比float慢得多。

msyql> create table tc_float(fid int primary key auto_increment,f_float float, f_float10 float(10), f_float25 float(25), f_float7_3 float(7,3), f_float9_2 float(9,2), f_float30_3 float(30,3), f_decimal9_2 decimal(9,2)); mysql> insert into tc_float(f_float,f_float10,f_float25) values(123456,123456,123456);mysql> insert into tc_float(f_float,f_float10,f_float25) values(1234567.89,12345.67,1234567.89);mysql> select * from tc_float;+—–+———-+———–+————+————+————+————-+————–+| fid | f_float | f_float10 | f_float25 | f_float7_3 | f_float9_2 | f_float30_3 | f_decimal9_2 |+—–+———-+———–+————+————+————+————-+————–+| 1 | 123456 | 123456 | 123456 | NULL | NULL | NULL | NULL || 2 | 1234570 | 12345.7 | 1234567.89 | NULL | NULL | NULL | NULL |+—–+———-+———–+————+————+————+————-+————–+

  • 可以看到float与float(10)是没区别的,float默认能精确到6位有效数字

mysql> insert into tc_float(f_float9_2,f_decimal9_2) values(123456.78,123456.78);mysql> insert into tc_float(f_float9_2,f_decimal9_2) values(1234567.1,1234567.125);Query OK, 1 row affected, 1 warning (0.00 sec) mysql> show warnings;+——-+——+—————————————————+| Level | Code | Message |+——-+——+—————————————————+| Note | 1265 | Data truncated for column ‘f_decimal9_2’ at row 1 |+——-+——+—————————————————+1 row in set (0.00 sec) mysql> select * from tc_float;+—–+———-+———–+————+————+————+————-+————–+| fid | f_float | f_float10 | f_float25 | f_float7_3 | f_float9_2 | f_float30_3 | f_decimal9_2 |+—–+———-+———–+————+————+————+————-+————–+| 6 | NULL | NULL | NULL | NULL | 123456.78 | NULL | 123456.78 || 9 | NULL | NULL | NULL | NULL | 1234567.12 | NULL | 1234567.13 |+—–+———-+———–+————+————+————+————-+————–+ mysql> insert into tc_float(f_float7_3) values(12345.1);ERROR 1264 (22003): Out of range value for column ‘f_float7_3’ at row 1

  • float(9,2)与decimal(9,2)是很像的,并没有前面提到24位一下6位有效数字的限制
  • 他们俩之间的差别就在精度上,f_float9_2本应该是 1234567.10,结果小数点变成 .12 。f_decimal9_2因为标度为2,所以 .125 四舍五入成 .13
  • 将 12345.1 插入f_float7_3列,因为转成标度3时 12345.100,整个位数大于7,所以 out of range 了

另外在编程中应尽量避免做浮点数的比较,否则可能会导致一些潜在的问题。

坚决不允许使用float去存money,使用decimal更加稳妥,但使用decimal做除法依旧会产生浮点型,所以特殊情况请考虑使用整型,货币单位使用 分 ,或者除法在最后进行。

Contents
  1. 1. int tinyint与bigint的比较
  2. 2. float和decimal