不要再被MYSQL的INT(M)给迷惑了
MYSQL里有些比较隐晦的知识点,经常被稀里糊涂的用错而不自知。以前评审过程发生的次数较多,索性随手写一些出来。前人栽个树,后人一定要乘凉啊!
表设计使用整型时,经常发现定义int括号里的M是五花八门的。误区是,不少人把M当成了数据库中存储的最大长度,而实际上这个代表的是显示宽度。只要是int类型,在数据库里的存储就一定是4个字节。
有符号整型:从-2^31(-2147483648) 到 2^31-1(2147483647)
无符号整型:从 0 到 2^32(4294967295)
那么这个M显示宽度到底怎么理解?这里先说个属性 zerofill(零填充)。因为只有用了这个属性,显示宽度才有存在的意义。
zerofill的作用说明:
1. 当一个数值列类型被定义成zerofill时,查询此列MYSQL会自动在数值左侧填充0直到M长度,若数值长度已超过M, 则无需填充0;
2. 声明为zerofill的数值列,默认会自动加上 unsigned(无符号) 属性。这个很容易理解,在一个负号前填充0是没什么意义的。
上例子。
Step 1 >
创建一张测试表,都是整型列,M分别定义为0,1,6,11,15。后缀为“z”的列被声明为zerofill。
细心的人可以发现:
- 没有标注unsigned的zerofill列,在表创建完成之后也会自动加上unsigned
- M为0的整型列,有符号自动定义为11,无符号自动定义为10
Step 2 >
插入测试数据100,10000000(8位),2147483647(有符号整型最大值),4294967295(无符号整型最大值), 9223372036854775807(有符号BIGINT最大值)。
Step 3 >
运行select查询全部数据。
Step 4 >
简单解读一下:
- 不管M定义多长,INT可存储的数值范围都由 4个字节 和 有无符号 来决定;
- 超过最大值不报错,直接存储最大值;
- 基于M显示宽度值来左填充0,只有声明zerofill的列才可以产生效果;
重申 >
若觉得使用int有点浪费,比如状态列,那可以使用tinyint, 千万不要想当然的以为int(1)存的是就一位数字,还沾沾自喜的觉得节省了存储空间。
题外话:
To be honest,MYSQL这个设计个人感觉是个失败品。不少人建议过应该取缔它,不管用LPAD()还是换成CHAR都可以实现这个功能,且不会产生歧义。日常编码也建议使用后面这两者。
推荐阅读