那天我在咖啡厅边敲代码边跟隔壁桌一哥们聊天,他说他们数据库里把VARCHAR(50)
全换成VARCHAR(500)
了,说啥以后灵活性高一点。我一口咖啡差点喷出来,我说你这不是埋雷嘛。
你要是没在项目里踩过这坑,真没法体会这俩有多大区别。很多人以为,这就是个长度的事儿,不就是50和500嘛,大不了存不下呗——其实坑可深了。
先说第一个被忽视的点:MySQL 的 VARCHAR 并不是固定长度的存储,它是变长的!
就是说你定义了 VARCHAR(500)
,不代表它就一定占500个字节,它只是你告诉MySQL这个字段最大能存多长,实际存多长,它就存多长,只不过它还得额外加个字节记录长度(如果你字段超过255字节,还得两个字节)。
我当时是晚上在家改一张表,给原来那个名字字段加长了点,本来 VARCHAR(50)
改成
VARCHAR(500)
,部署上去系统直接卡了,慢查询狂飙……后来才发现这玩意影响到InnoDB的行格式、页存储结构、甚至索引的存储方式。
比如这样一个建表语句:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
bio VARCHAR(500)
);
你注意啊,username
就算用 UTF-8 编码,最长占用 150 字节(1个汉字3个字节),但是 bio
这个 VARCHAR(500)
就可能占 1500 字节。
再想想 InnoDB 默认一页 16KB,一条记录一多,能放的行数就变少了,我以前有个表字段加长了,原来一页能放上百行,后面只剩五六十,查询范围稍微一广,Buffer Pool根本Hold不住。
索引就更不能瞎整了
有次我们做模糊搜索,需要给一个 VARCHAR(500)
字段加个前缀索引。
CREATE INDEX idx_bio ON users (bio(100));
MySQL支持你对长字段建“前缀索引”,但你真要全字段建索引?别闹,InnoDB的索引长度是有限的,UTF-8下最大767字节,超过就报错不让建,或者让你改成 DYNAMIC 行格式(用 ROW_FORMAT=DYNAMIC
)。
然后你拼命查资料才发现,之前的 VARCHAR(50)
根本不用管这事,直接上索引没问题,500就得各种折腾。
JVM连锁反应也有
我之前写个 Java 接口做表单入库,@RequestParam("bio") String bio
,看着好像没事,结果有用户复制粘贴从网页扒来一堆乱码,全是 emoji + 日文,MySQL 一 insert 直接炸,中文 emoji 那种4字节字符都超过 VARCHAR(500)
上限。
改了后接口也要同步改验证,不然数据层报错,应用层一脸懵。
别看
VARCHAR(50)
和 VARCHAR(500)
只差一个零,这个零背后的锅,可能让你写的代码、建的索引、配的缓存全翻车。
我的建议?字段大小是设计时就得好好定的,不是越大越好,是刚刚好才好。真有可能超长的地方,用 TEXT
或 LONGTEXT
,反而更稳定,当然代价你自己掂量。
哦对,我当时是加班改这个bug搞到凌晨三点,第二天一早还得开会……所以别随便改长度,改之前多问问DBA,真别嫌麻烦。你说是不是?
-END-
我为大家打造了一份RPA教程,完全免费:https://www.songshuhezi.com/rpa.html