MySQL面试必问:存储用户密码,char还是varchar?答案出乎意料!

2,991 阅读6分钟



大家好呀,我是小米,一个31岁依旧在代码世界里乐此不疲的技术“打怪升级者”。最近又遇到一位小伙伴吐槽:去面试MySQL相关岗位,面试官抛了一个看似“很小”的问题,结果他翻车了。问题是这样的:

“如果要存储用户的密码散列,应该使用什么字段进行存储?”

小伙伴一听,心想:这不就是 varchar 吗?我平时不都是这么写吗?于是胸有成竹地答道:varchar(255)

结果面试官微微一笑,说:“能不能解释下,为什么是 varchar,为什么不是 char?散列长度你考虑过没?不同算法存储上有什么区别?”

小伙伴瞬间石化。

于是,他面试挂了,回头来找我诉苦。听完之后,我忍不住乐了:

这其实是一个面试官用来区分‘只会CRUD’和‘真正懂数据存储细节’的好问题。

今天,我就借着这个故事,带大家一起深入拆解这道题。保证你看完后,不仅能搞清楚存储密码散列的最佳实践,还能顺带复盘一堆关于MySQL字段设计的底层知识。

为什么密码要存储“散列值”?

先别急着讨论字段类型,我们得先弄清楚为什么要存储“密码散列”。

很多小伙伴做项目的时候,图省事,喜欢把用户密码直接存数据库,比如:

这就相当于把银行金库的钥匙,直接放在金库门口。只要库被拖走,所有用户的密码就等于裸奔。

正确做法:存储的是密码的 散列值(hash) ,例如通过 SHA-256、bcrypt、argon2 之类的算法处理后再入库。这样,即便数据库泄露,攻击者拿到的也是一堆“乱码”,想逆推出原始密码的难度极高。

所以,数据库中真正要存储的,不是 123456,而是像这样的一串散列:

这就引出了第一个关键点:密码散列是定长的字符串,而不是无限长的文本。

散列值到底多长?

在面试时,很多人第一反应是 varchar(255),因为这似乎是万能解法。

但其实,散列算法有明确的输出长度:

  • MD5 → 128 位 → 32 个十六进制字符
  • SHA-1 → 160 位 → 40 个十六进制字符
  • SHA-256 → 256 位 → 64 个十六进制字符
  • SHA-512 → 512 位 → 128 个十六进制字符
  • bcrypt → 固定 60 个字符(含盐)
  • argon2 → 通常可配置,推荐 95 个字符左右

注意,这些都是“定长输出”,意味着我们完全可以针对性地选择字段长度,而不是盲目用 varchar(255)。

所以,当面试官问你时,你要能答得清楚:

  • 如果项目明确用了 SHA-256,那么你完全可以定义为 char(64)。
  • 如果考虑灵活性,比如未来可能换成更安全的 SHA-512 或 argon2,可以设置 char(128) 或 varchar(200),给自己留扩展空间。

char 还是 varchar?

这是面试官最爱“挖坑”的地方。

1、char(n)

  • 固定长度,不足时会自动填充空格。
  • 查询速度快,因为存储是定长的,定位更容易。
  • 对于散列这种“定长字符串”,char 更加合适。

2、varchar(n)

  • 可变长度,存储空间更灵活。
  • 如果密码散列长度固定,用 varchar 就有点浪费了。

举个例子:

如果你存的是 SHA-256 散列:

这才是最佳选择。如果你写成:

虽然功能上没问题,但面试官会觉得你不够“专业”,因为你没有结合密码散列的特性来选择字段类型。

加盐(salt)和字段设计

说到密码散列,就一定会谈到“加盐”。

所谓“盐”,就是在密码前后加上一段随机字符串,再去做散列。比如:

这样,即使两个用户的密码一样,数据库里的散列值也会不同。

那问题来了:盐要不要存数据库?

答案是:要存,而且通常和散列分开存。

常见的设计是这样的:

这样,你既能保存用户密码的散列值,也能保存对应的盐,验证时再拼接计算。

现实中的字段设计方案

为了让你在面试里能答出一套“体系化的答案”,我整理了几种实际可行的字段设计:

方案1:仅存散列

适合只用 SHA-256,不考虑切换算法的情况。

方案2:散列 + 盐

安全性更高,适合有长期运营的系统。

方案3:通用可扩展方案

这里不仅保存散列,还保存算法名,方便未来切换到更强的算法,比如 argon2。

这一套回答,面试官听完会很满意,因为你不光考虑了“字段类型”,还把“未来演进、算法安全”都考虑进去了。

实战故事:我曾经踩过的坑

我还记得自己第一次写用户系统时,图省事:

当时项目上线没多久,用户量一多,问题就来了:

  1. 索引效率下降:因为 varchar(255) 太长,MySQL 在建索引时效率低。
  2. 数据浪费:散列值明明只有 64 个字符,却每次都多存一大堆空闲空间。
  3. 迁移麻烦:后来我们想改用 bcrypt,结果发现长度不匹配,整个表都要改字段。

从那之后,我就再也不乱用 varchar 了,而是严格根据算法来设计字段。

总结一下(面试答题模版)

如果你在面试中遇到这个问题,可以按以下思路回答:

  • 首先强调安全性:密码必须存散列而不是明文,并且推荐加盐。
  • 结合算法谈长度
    • MD5 → char(32)
    • SHA-256 → char(64)
    • SHA-512 → char(128)
    • bcrypt → char(60)
    • argon2 → varchar(200)(可变长)
  • 选择 char 而不是 varchar:因为散列是定长的。
  • 可扩展设计:如果考虑未来算法升级,可以增加 algorithm 字段。

这样,你的回答不仅全面,还能体现出对安全和数据库底层存储的理解。

结语

你看,这道看似“小儿科”的题,其实能看出一个程序员的思维深度:

  • 只会回答 varchar(255),说明只是停留在“会用”层面;
  • 能答出“根据算法定长存储、加盐设计、考虑扩展”,说明是真正理解了数据库和安全的结合点。

所以,如果你下次面试再遇到这类问题,不要慌,大大方方答出来,面试官会对你刮目相看。

END

安全永远是用户系统的第一道防线,密码散列字段设计虽小,却能体现你对系统设计的严谨程度。愿大家都能在面试时答出漂亮的答案,不再掉坑!

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!