选型核心是“刚好够用且最省”,而非“哪个能用”;int(11)的11仅为显示宽度,与存储能力无关,int恒占4字节、tinyint恒占1字节,精度和范围由类型本身决定。

直接说结论:选型不是“哪个能用”,而是“哪个刚好够用且最省”。用大类型存小数据,迟早拖垮磁盘、内存和查询速度。
INT(11) 和 TINYINT 本质区别在哪
很多人看到 INT(11) 就以为它比 TINYINT “能存更多”,其实完全误解了。INT(11) 的 11 只是显示宽度(比如配合 ZEROFILL),和存储能力毫无关系——INT 永远占 4 字节,TINYINT 永远占 1 字节。
- 年龄字段用
TINYINT UNSIGNED(0–255)足够,没必要上INT - 状态字段(如启用/禁用)用
TINYINT(1)或更干脆的TINYINT NOT NULL DEFAULT 0,别写成INT或VARCHAR - 如果业务明确不会超 65535(比如部门编号),
SMALLINT UNSIGNED比INT省 2 字节,百万行表就省下约 2MB 存储
DECIMAL(10,2) 为什么不能换成 FLOAT
FLOAT 和 DOUBLE 是二进制浮点数,计算结果不精确;DECIMAL 是定点数,按十进制精确存储。哪怕只是存个价格,用 FLOAT 也可能导致 0.1 + 0.2 = 0.30000000000000004 这种问题。
- 所有金额、费率、积分余额等必须用
DECIMAL(M,D),常见写法是DECIMAL(10,2)(最大 99999999.99) -
M是总位数(精度),D是小数位数(标度),D不能大于M-1(至少留一位整数位) - 不要写
DECIMAL(19,4)除非真需要 15 位整数——过大反而影响排序和索引效率
VARCHAR(255) 不是万能默认值
把所有文本字段都设成 VARCHAR(255),看似保险,实则埋雷。MySQL 对 VARCHAR 字段建索引时,默认只索引前 767 字节(utf8mb4 下约 191 字符),超出部分无法参与索引查找。
- 手机号固定 11 位,用
CHAR(11)更高效(定长、无额外长度字节开销) - 邮箱一般 ≤ 254 字符,但实际业务中多数 ≤ 64,可设
VARCHAR(128)并加唯一索引 - 商品标题、用户昵称这类真正变长的字段,才用
VARCHAR;长度明显固定(如国家代码CHAR(2))或极短(如性别CHAR(1)),优先CHAR - 避免对
TEXT字段直接加普通索引——要么用前缀索引(INDEX(title(100))),要么改用全文索引(FULLTEXT)
DATETIME vs TIMESTAMP 怎么选
两者都存日期时间,但行为差异很大:TIMESTAMP 会自动转成 UTC 存储、读取时转回当前时区;DATETIME 原样存储,不涉及时区转换。
- 记录创建/更新时间(如
created_at、updated_at),用TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP最省心 - 业务意义明确的时间点(如用户生日、订单发货时间),用
DATETIME,避免时区错乱 -
TIMESTAMP范围窄(1970–2038),超范围会报错或截断;DATETIME范围宽(1000–9999),更安全 - 不要用
INT存 Unix 时间戳——失去 MySQL 内置时间函数支持(如DATE_ADD、YEAR()),也难读
最易被忽略的一点:字段是否 NOT NULL 比类型本身影响更大。一个可为空的 TINYINT,在索引里可能比非空的 INT 更慢——NULL 值让优化器更难估算统计信息,也增加索引存储开销。











