那天我在公司茶水间碰到测试那哥们,手里拿着杯咖啡跟我说他们库有个表的字段用了varchar(500),然后问我说跟varchar(50)有啥区别。我一边泡茶一边琢磨,这事儿说大不大,但真能把人绕进去,尤其是那种看似“随便定个长度”的做法,其实背后藏了不少坑。
字面上的区别是假的,内核里的差别才真
你看啊,varchar(50)和varchar(500)表面上不就是个数字变大了嘛,感觉好像只是“能存更多字符”对吧?但问题不是这么简单。MySQL 的varchar是变长字符串嘛,它不是定死多少个字节去存,而是你存多长就占多长,再加个额外的“长度字节”来标记真实长度。
这个“长度字节”就有说法了,小于等于255长度的字段只用1个字节来存长度信息,如果你上了256,那就需要两个字节。所以你用varchar(500),它每条记录就多消耗一个字节,用多了表大了,磁盘I/O就跟着多。
影响索引那块,有点坑
这点是我之前踩过的坑,我们组的小李就因为这个被DBA找过。InnoDB 的前缀索引有个限制,它最多只能索引767字节(之前版本),utf8 编码下一个字符最多占3字节,那你想啊,varchar(500)就可能炸索引了,搞不对直接报错:Specified key was too long。
举个简单例子:
CREATE TABLE user (
username VARCHAR(500),
INDEX idx_username(username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
你一执行这玩意就可能出事。但你换成varchar(50)就稳了,50×3=150,还远没到767的极限。
char 和 varchar 傻傻分不清?
还有人会说,那干脆用char(500)岂不是更好?哎兄弟你可别乱搞,char是定长的,500就是死命占500字符,不管你真写几个。这种设计不适合大多数实际应用场景,除非你明确知道每一行就固定长度,比如身份证号那种。一般业务字段你就老老实实用varchar,但别膨胀得太离谱。
真正的设计考量:业务用多少就写多少
我记得那会儿我们公司重构用户表,有个字段叫nickname,之前写的是varchar(255),其实压根没哪个用户起那么长的昵称。最后我们给压成了varchar(64),然后联合索引立马就能用了,查询速度直接提了两三倍。
你自己写代码的时候也能感受到,如果你用 Hibernate 或 MyBatis 写的映射类,字段特别长可能生成的实体对象也很奇怪,调试起来不顺眼。
来点代码测一下
我那天手痒,在本地写了俩表测了一下存储空间占用:
CREATE TABLE test_50 (
name VARCHAR(50)
) ENGINE=InnoDB;
CREATE TABLE test_500 (
name VARCHAR(500)
) ENGINE=InnoDB;
然后我分别插了 10000 行长度为 10 的字符串,用information_schema.TABLES看表大小,你猜咋着?test_500比test_50足足多出了几百KB,虽然不是很大,但想想上百万行就会积累成灾。
结尾:别看着数字大就香
总结一句话,varchar(50)和varchar(500)不是说你想用大点就能随便大点的,这玩意就像是你买鞋,不合脚你就别凑合,踩起来累。除非你确定那个字段真的可能存很长的内容,否则用短一点的varchar,对你对数据库都好。性能、安全、索引空间,各方面都稳。
哦对了,我茶水都泡完了,那哥们还在琢磨他的数据库字段,我就跟他说:你字段到底是昵称、邮箱、地址还是UUID啊,不一样的用法,长度都该不一样,别图省事全都写个500……
说实话我后来想想,还有人连 varchar 的长度单位都搞混,以为是字节……这又得单聊一小时,下次有空我再说吧。