别用varchar(255)定义数据库字段

224 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

我有个朋友每次写sql建表都使用varchar(255)声明字段,还好做的项目不用考虑性能问题,能跑就行不然就麻烦大了。

使用varchar(255)的经历

mysql对于变长字段varchar会用额外一两个字节保存长度,当长度小于255个字节时,使用一个字节记录字符串的长度。如果大于255就使用两个字节保存字符串长度。所以就容易得出这么一个结论,如果保存的字段不会大于255的话直接使用varchar(255)就行了,因为保存数据255字节都一样额外用一个字节来保存长度信息。于是就会出现大量这样的sql。

image.png

遇到varchar(255)的坑

有一天建立一个表的时候遇到了字段varchar(255)报错超长,就说255超长了,查资料发现索引不能太长,索引长度不能超过767,一般用UTF8编码,UTF8编码一个字符占用4个字节,varchar(255)中的255表示字符而不是字节,那么255*4>767,超长了。如果字段就是需要设计那么长那么也可以进行截断,建立索引时加括号()截断例如unique (username(100)) ,是不是以后使用utf8的时候定义字段这样子varchar(255/4)

突然想到一个问题,mysql设计者为什么不直接设置两种枚举,一种刚好使用一个字节保存字符串长度的,一种是使用两个字节保存字符串长度的,即只提供varchar(255)和varchar(65535)两种选择不就得了,为啥要设计成用户可以自由设置长度?难道他们没想到吗?肯定是有原因的。

结论

经过进一步查资料发现,varchar(255)和varchar(5)保存字符串“aaaaa”使用磁盘空间一样的。但是当数据被读出来内存的时候,占用内存就不一样了,比如将数据从存储引擎层复制到SQL层时,VARCHAR将转换字段CHAR以获得利用固定宽度行的优势。因此,内存中的字符串将填充到声明的VARCHAR列的最大长度。例如varchar(255)和varchar(5)保存字符串“aaaaa”读取到内存varchar(255)声明的字段占用255的内存,但是varchar(5)声明的字段占用5的内存。还有当查询隐式生成临时表时(例如在排序或是GROUP BY)也是一样会根据定义的长度分配内存而不是根据实际保存数据的多少。如果使用很多VARCHAR(255)字段来存储不需要那么长的数据,这会使临时表变得非常大。严重影响数据库的性能。

用多少就设置多少,别偷懒啦