面试知识库
基础

char与varchar选型#

一句话答案#

char 是定长(不足补空格、存取时去空格),适合长度固定或近似固定的短字段(如手机号、MD5、状态码);varchar 是变长(按实际长度存 + 1~2 字节记长度),适合长度波动大的字段;选型核心是”长度是否固定、是否频繁更新、能否省空间换不产生行迁移”。

核心要点
维度char(N)varchar(N)
存储固定 N 个字符,不足补空格实际长度 + 1~2 字节长度前缀
上限最多 255 字符受行大小限制(最大 65535 字节,约几万字符)
取值读取时去掉尾部空格(尾部空格丢失)原样存取,保留空格
适用长度固定/近似固定的短串:手机号、身份证、MD5、UUID、status长度波动大的串:用户名、地址、备注、标题
更新定长,原地更新,不易产生行迁移变长,变长可能导致页内移动甚至行迁移

字段类型选型通用原则:

  • 够用就好:能用 int 不用 bigint,能用 tinyint 表状态不用 int,越小的字段索引和缓存效率越高
  • 整数优先于字符串:枚举/状态用 tinyint 而非字符串;IP 可用 int unsigned
  • 金额用 decimal:禁止 float/double 存钱,浮点有精度误差
  • 时间用 datetimetimestamptimestamp 占 4 字节带时区、范围到 2038,datetime 占 8 字节范围更大
  • 避免 text/blob 进主表:大字段拆到扩展表,避免拖慢主表扫描和回表
面试回答(2分钟版)

char 和 varchar 的核心区别是定长还是变长。char(N) 永远占 N 个字符,存不满会用空格补齐,读出来时尾部空格会被去掉;varchar(N) 是变长,实际存多少占多少,再额外加 1 到 2 个字节记录长度(长度小于 255 用 1 字节,否则 2 字节)。所以选型上:长度固定或几乎固定的短字段用 char,比如手机号、身份证、MD5 值、状态码,定长还有个好处是更新时长度不变、原地改不容易产生行迁移;长度波动大的字段用 varchar,比如用户名、地址、备注,能按需省空间。

再往上说字段类型选型的通用原则就是”够用就好、越小越好”:状态枚举用 tinyint 别用字符串,金额一定用 decimal 不能用 float/double 否则有精度问题,时间用 datetime 或 timestamp,大文本 text/blob 尽量拆到扩展表别放主表,否则会拖慢主表扫描。字段越小,单页能放的行越多,索引和 Buffer Pool 的命中率就越高,整体查询更快。

追问与易错

追问方向:

  • “char 一定比 varchar 快吗?”→ 不一定。char 定长便于原地更新、对频繁更新的定长字段有利;但 char 会浪费空间(补空格),存储变大反而降低页内行数。短且定长用 char,其余用 varchar
  • “varchar(255) 和 varchar(50) 存同样数据占用一样吗?”→ 磁盘存储一样(变长按实际长度),但内存里某些操作(如排序用的临时表、内存表)可能按声明的最大长度分配,所以别无脑开 255
  • “为什么金额不能用 float?”→ float/double 是二进制浮点,0.1 这类十进制小数无法精确表示,累加会产生误差,金额必须用 decimal 定点数
  • “时间字段 datetime 和 timestamp 怎么选?”→ timestamp 4 字节、带时区转换、范围 1970~2038(有 2038 问题);datetime 8 字节、不带时区、范围更大。需要时区敏感或省空间用 timestamp,否则用 datetime

易错点:

  • ❌ 用 char 存变长字段——浪费空间且尾部空格被截断,可能导致数据”被改”
  • ❌ 用 float/double 存金额——精度丢失,财务对不上账
  • ❌ 字段无脑开 varchar(255) 甚至更大——影响内存临时表和排序效率
  • ❌ 状态枚举用字符串存——浪费空间、索引效率低,应用 tinyint + 应用层映射