一、哪些类型支持 (M,D) 这种双参数格式
-
FLOAT(M,D)/DOUBLE(M,D)/DECIMAL(M,D)这三类是数值带小数 ,
M总位数、D小数位,双参数才有实际约束意义。 -
INT、TINYINT、BIGINT 等整型:只有
INT(M),没有第二个参数D写法只能
INT(5),不能INT(5,2),语法直接报错。
二、重点:INT(M) 完全没有"限制存储数字大小"的作用
很多人踩坑:
-
INT(5)里的 5不是最多存5位数字,和取值范围无关 -
INT 本身固定范围:
-2147483648 ~ 2147483647,不管括号写多少,都能存这么大的数 -
M叫显示宽度 ,仅配合ZEROFILL零填充才生效:sqlid INT(5) ZEROFILL; -- 插入数字1,查询出来显示 00001
不加 ZEROFILL 时,括号里的数字毫无作用 ,写 INT(3)、INT(11)、INT(20) 完全等价。
INT(M) 本身无任何数值长度限制,不加零填充时写多少都没意义,开发规范里不建议给INT加括号长度 ,直接写 INT 即可。
补充开发规范
- 金额、数量小数:用
DECIMAL(总位,小数位) - 普通整数id、数量:直接
INT/BIGINT,不要写INT(11)这种过时写法 - 浮点数业务尽量少用float/double,精度丢失风险高
类型(M, D)
类型(M, D):M=总有效数字长度,D=小数位数
float(5,2)
- M=5:总共最多存5个数字
- D=2:其中2位是小数
- 整数位最多:
5-2=3位
取值范围:-999.99 ~ 999.99
示例:
123.45 ✅(3整数 + 2小数 = 5位)
1234.5 ❌ 整数4位超了
decimal(6,2)
- M=6:总共6个数字
- D=2:2位小数
- 整数位最多:
6-2=4位
取值范围:-9999.99 ~ 9999.99
示例:
9999.99 ✅
10000.00 ❌
重要区别:float 和 decimal 本质不一样
-
float 浮点型
近似存储,会有精度丢失,不适合金额、财务计算;
float(M,D) 只是显示约束,底层存储还是二进制浮点数。
-
decimal 定点高精度
十进制精确存储,无精度误差,金额、价格必须用 decimal。
补充小知识点
如果插入数值小数超出D位,MySQL会四舍五入 截断;
整数超出总长度则直接报错。
例:decimal(6,2) 插入 1234.567 → 自动存 1234.57
怎样,定义数据类型
在定义数据类型时,
-
如果确定是整数,就用INT;
-
如果是小数,一定用定点数类型DECIMAL(M,D);
-
如果是日期与时间,就用DATETIME。
这样做的好处是,首先确保你的系统不会因为数据类型定义出错。
不过,凡事都是有两面的,可靠性好,并不意味着高效。
比如,TEXT虽然使用方便,但是,效率不如CHAR(M)和VARCHAR(M)。
1. 整数用int、小数用decimal、时间用datetime ------ 保证数据可靠
(1)整数统一 INT(业务主键、数量、ID)
- 不用 float/double 存整数:浮点会出现
100 ≠ 100.0、求和累加失真、等值查询走不上索引; - 不推荐 TINYINT / SMALLINT 过度抠空间:除非千万级超大表,普通业务 INT 4字节足够,可读性、兼容性更强;
- 规范写法:直接写
INT,不要写INT(11)这种无意义显示宽度。
(2)小数一律 DECIMAL(M,D),严禁 float / double 存金额、价格、比例
float/double 二进制近似存储,0.1、0.2 无法精确保存,加减乘除多次运算误差会累积,对账、财务直接出坏账。
- 商品价格:
DECIMAL(10,2)(最大千万,两位小数) - 税率、折扣:
DECIMAL(5,2)
(3)日期时间优先 DATETIME,不要用 VARCHAR、INT 存时间
- VARCHAR 存时间:无法用时间函数
date_add、区间索引失效、排序错乱; - TIMESTAMP 有时间范围限制(1970~2038),跨年份业务易踩坑;
- DATETIME 范围 1000-01-01 ~ 9999-12-31,通用稳定,支持时分秒,绝大多数业务首选。
以上这样,核心收益:从底层杜绝精度丢失、类型隐式转换、索引失效、时间逻辑bug,业务数据不会因类型定义出错。
2. 可靠性高 ≠ 性能最优,字符串类型效率分层:CHAR > VARCHAR > TEXT
底层效率差异原因(InnoDB)
-
CHAR(M) 定长字符串
每行占用固定字节,数据库不需要读取长度标识,行偏移计算极快;更新不会产生页分裂;索引紧凑,查询速度最快。
适用:手机号
CHAR(11)、身份证CHAR(18)、性别CHAR(1)、MD5。 -
VARCHAR(M) 变长短文本
存储 = 实际字符 + 1~2字节长度前缀,读写多一步长度解析;更新变长时容易页分裂;但比 TEXT 快很多。
适用:用户名、标题、地址、摘要(长度可控,几百字符以内)。
-
TEXT(TINYTEXT / TEXT / MEDIUMTEXT / LONGTEXT)效率最低
- TEXT 字段不和普通行存在一起,行内只存20字节指针,查询时要二次读取溢出页;
- 无法创建完整前缀索引、排序、分组性能极差;
- 频繁查询 TEXT 会大量增加IO,拖慢全表速度。
适用:文章正文、大段备注、富文本,仅少量读取、极少作为查询条件的字段。
补充修正(避坑关键点)
1. DATETIME 不是万能,特殊场景有替代
- 仅存年月日、不需要时分秒:用
DATE(3字节,比DATETIME省空间); - 需要自动记录创建/更新时间、时区无关日志:
TIMESTAMP; - 毫秒级时间戳:可 BIGINT 存时间戳,但展示、区间筛选不如 DATETIME 直观。
2. DECIMAL 可靠但运算性能弱于 float/double
DECIMAL 是软件十进制运算,CPU无硬件加速;float/double 由浮点寄存器直接计算,速度快几倍。
取舍规则:
- 财务、金额、对账:牺牲性能,必须 DECIMAL;
- 传感器数值、科学统计、误差允许:可用 DOUBLE。
3. VARCHAR 不是一无是处,绝大多数场景优先于 CHAR
CHAR 以空间换速度,短且固定长度才划算;
姓名、商品名称、地址长度参差不齐,VARCHAR 更省磁盘,整体吞吐量更高,是日常字符串默认选择。
以下是一套可直接落地的字段选型规范
数值
- 普通整数ID、数量:
INT - 超大主键、流水号:
BIGINT - 金额、小数计算:
DECIMAL(总长度, 小数位) - 非精密统计浮点:
DOUBLE
时间
- 完整年月日时分秒通用:
DATETIME - 仅日期:
DATE - 自动更新时间戳:
TIMESTAMP
字符串(按性能从高到低)
- 固定短值:
CHAR(M) - 可控长度短文本:
VARCHAR(M)(业务最常用) - 大段正文、超长备注:
TEXT(尽量少用,不建索引)
MySQL5.7 varchar / char 选型 + 字符长度规则
一、先搞懂:字符 vs 字节(MySQL5.7 核心)
1. 字符长度规则(utf8mb4 / utf8)
MySQL5.7 常用两种字符集:
- utf8mb4(推荐,支持完整汉字、emoji)
- 1个汉字 = 1个字符,占4字节
- 字母/数字/英文符号 = 1个字符,占1字节
- utf8(mysql阉割版,不支持emoji)
- 1个汉字 = 1个字符,占3字节
- 字母 / 数字 / 英文符号 = 1个字符,占1字节
重点:
VARCHAR(20)、CHAR(20)括号里写的是字符数 ,不是字节数!不管汉字、字母、数字、标点,全都统一算「1个字符」。
举例:
VARCHAR(10) 最多存:
- 10个英文字母
- 10个汉字
- 5汉字+5数字,总数不超10个字符
2. 中文全角符号(,。!)
也算1个字符 ,占用3/4字节;英文半角 ,.! 1字符1字节。
二、CHAR 和 VARCHAR 区别 & 怎么选
1. CHAR(n) 定长字符串
特性:
- 固定占用
n个字符空间,数据不足会空格补全,查询时自动去掉尾部空格 - 最大长度:CHAR(0) ~ CHAR(255)
- 性能:读取更快,无需计算长度;更新几乎无碎片
- 缺点:短内容浪费存储空间
适用场景(固定长度必选CHAR):
- 手机号 CHAR(11)
- 身份证 CHAR(18)
- 银行卡号、验证码、状态码(长度永远固定)
例:手机号 CHAR(11),存11位数字,空间刚好,查询速度最优。
2. VARCHAR(n) 变长字符串
特性:
- 存多少占多少空间,额外加1~2字节记录长度
- MySQL5.7 单行总字节限制65535,单字段理论最大可到VARCHAR(65532)
- 数据长短差异大时节省空间;频繁更新会产生碎片,略慢于CHAR
适用场景(长度不固定,90%业务都用这个):
- 用户名、姓名、地址、备注、商品名称、简介
- 长短不一的文本
三、选型口诀
- 长度永远固定 → CHAR
手机号、身份证、编号、验证码 - 长度不固定、长短差异大 → VARCHAR
姓名、地址、描述、备注、标题 - 超过255字符的文本(简介、详情)→ 用
TEXT,别用超大VARCHAR
四、补充注意事项(MySQL5.7)
- 字符集统一用
utf8mb4,不要用旧utf8,否则存不了表情包、生僻汉字 - 不要滥用
CHAR(255)存不固定短文本,极度浪费磁盘 - 查询过滤时:
CHAR字段尾部空格自动忽略,VARCHAR严格区分空格
sql
-- char字段,'13800001111' 和 '13800001111 ' 查询结果一样
where phone = '13800001111'
- 索引:CHAR、VARCHAR 都可以建索引,但过长VARCHAR建索引要设置前缀长度
index idx_name(name(50))
举个业务实例
- 姓名:VARCHAR(20)(有的人2个字,有的人4个字)
- 身份证号:CHAR(18)(固定18位)
- 用户地址:VARCHAR(200)
- 短信验证码:CHAR(6)
- 商品简介:VARCHAR(500)
- 商品详情:TEXT