mysql 的经验

一、哪些类型支持 (M,D) 这种双参数格式

  1. FLOAT(M,D) / DOUBLE(M,D) / DECIMAL(M,D)

    这三类是数值带小数M总位数、D小数位,双参数才有实际约束意义。

  2. INT、TINYINT、BIGINT 等整型:只有 INT(M),没有第二个参数D

    写法只能 INT(5),不能 INT(5,2),语法直接报错。

二、重点:INT(M) 完全没有"限制存储数字大小"的作用

很多人踩坑:

  • INT(5) 里的 5不是最多存5位数字,和取值范围无关

  • INT 本身固定范围:-2147483648 ~ 2147483647,不管括号写多少,都能存这么大的数

  • M显示宽度 ,仅配合 ZEROFILL 零填充才生效:

    sql 复制代码
    id 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 本质不一样

  1. float 浮点型

    近似存储,会有精度丢失,不适合金额、财务计算;

    float(M,D) 只是显示约束,底层存储还是二进制浮点数。

  2. 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)

  1. CHAR(M) 定长字符串

    每行占用固定字节,数据库不需要读取长度标识,行偏移计算极快;更新不会产生页分裂;索引紧凑,查询速度最快。

    适用:手机号 CHAR(11)、身份证 CHAR(18)、性别 CHAR(1)、MD5。

  2. VARCHAR(M) 变长短文本

    存储 = 实际字符 + 1~2字节长度前缀,读写多一步长度解析;更新变长时容易页分裂;但比 TEXT 快很多。

    适用:用户名、标题、地址、摘要(长度可控,几百字符以内)。

  3. 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

字符串(按性能从高到低)

  1. 固定短值:CHAR(M)
  2. 可控长度短文本:VARCHAR(M)(业务最常用)
  3. 大段正文、超长备注:TEXT(尽量少用,不建索引)



MySQL5.7 varchar / char 选型 + 字符长度规则

一、先搞懂:字符 vs 字节(MySQL5.7 核心)

1. 字符长度规则(utf8mb4 / utf8

MySQL5.7 常用两种字符集:

  1. utf8mb4(推荐,支持完整汉字、emoji)
    • 1个汉字 = 1个字符,占4字节
    • 字母/数字/英文符号 = 1个字符,占1字节
  2. 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) 定长字符串

特性:

  1. 固定占用 n 个字符空间,数据不足会空格补全,查询时自动去掉尾部空格
  2. 最大长度:CHAR(0) ~ CHAR(255)
  3. 性能:读取更快,无需计算长度;更新几乎无碎片
  4. 缺点:短内容浪费存储空间

适用场景(固定长度必选CHAR):

  • 手机号 CHAR(11)
  • 身份证 CHAR(18)
  • 银行卡号、验证码、状态码(长度永远固定)

例:手机号 CHAR(11),存11位数字,空间刚好,查询速度最优。

2. VARCHAR(n) 变长字符串

特性:

  1. 存多少占多少空间,额外加1~2字节记录长度
  2. MySQL5.7 单行总字节限制65535,单字段理论最大可到VARCHAR(65532)
  3. 数据长短差异大时节省空间;频繁更新会产生碎片,略慢于CHAR

适用场景(长度不固定,90%业务都用这个):

  • 用户名、姓名、地址、备注、商品名称、简介
  • 长短不一的文本

三、选型口诀

  1. 长度永远固定 → CHAR
    手机号、身份证、编号、验证码
  2. 长度不固定、长短差异大 → VARCHAR
    姓名、地址、描述、备注、标题
  3. 超过255字符的文本(简介、详情)→ 用 TEXT,别用超大VARCHAR

四、补充注意事项(MySQL5.7)

  1. 字符集统一用 utf8mb4,不要用旧 utf8,否则存不了表情包、生僻汉字
  2. 不要滥用 CHAR(255) 存不固定短文本,极度浪费磁盘
  3. 查询过滤时:CHAR 字段尾部空格自动忽略,VARCHAR 严格区分空格
sql 复制代码
-- char字段,'13800001111' 和 '13800001111  ' 查询结果一样
where phone = '13800001111'
  1. 索引:CHAR、VARCHAR 都可以建索引,但过长VARCHAR建索引要设置前缀长度 index idx_name(name(50))

举个业务实例

  • 姓名:VARCHAR(20)(有的人2个字,有的人4个字)
  • 身份证号:CHAR(18)(固定18位)
  • 用户地址:VARCHAR(200)
  • 短信验证码:CHAR(6)
  • 商品简介:VARCHAR(500)
  • 商品详情:TEXT
相关推荐
数据库小学妹2 小时前
MySQL高可用架构选型实战:MHA vs MGR vs InnoDB Cluster原理对比与性能实测
mysql·mgr·mha·架构选型·mysql高可用
ywl4708120873 小时前
Mysql,使用B+树存储的索引增删改查效率(七)
数据库·b树·mysql
我叫黑大帅13 小时前
MySQL 并发插入竞态问题:原子写入实践指南
后端·mysql·面试
我会尽全力 乐观而坚强14 小时前
MySQL零基础入门(二)
数据库·mysql·adb
龙石数据17 小时前
MySQL 全量同步到 Hive 怎么做?三步配置教程
数据库·hive·mysql·数据治理·数据中台
白露与泡影21 小时前
慢 SQL 不一定是 SQL 慢:一次 MySQL 连接池耗尽的故障定位
数据库·sql·mysql
还是鼠鼠1 天前
AI掘金头条新闻系统 (Toutiao News)-缓存相关推荐新闻
后端·python·mysql·fastapi·web
宠友信息1 天前
Redis 内容社区源码架构优化与即时通讯数据一致性处理
spring boot·后端·websocket·mysql·uni-app
霸道流氓气质1 天前
Kiro 配置 MySQL MCP Server 通用教程
数据库·mysql·adb·mcp·kiro