MySQL varchar(255) 的秘密
·
很多人写表结构的时候,习惯性地写 VARCHAR(255),觉得 255 是标准值。为啥是 255?有啥讲究?这篇说清楚。
255 哪来的?
ASCII 码的范围是 0127,一个字符占一个字节。加上符号,128255 也可以用一个字节存。所以 255 是单字节字符串的最大长度。
但 MySQL 里 VARCHAR 的长度单位是字符,不是字节。对于 UTF8MB4,一个中文算 1 个字符,但占 4 个字节。
VARCHAR 的存储机制
-- VARCHAR(255) 的存储结构
-- [长度前缀] + [实际数据]
-- 长度前缀:1 或 2 字节(255 以内用 1 字节)
示例
-- 存 "abc"(3字节)
-- 实际存储:[03 61 62 63] = 长度3 + "abc"
-- 存 "中文字符"(5个字符,15字节)
-- 实际存储:[05 E4 B8 AD E6 96 87 E5 AD 97 E7 AC A6] = 长度5 + 15字节数据
VARCHAR 最大能存多少?
-- MySQL 行大小限制 65535 字节
-- VARCHAR 最大 = 65535 - 2(长度前缀)= 65533 字节
CREATE TABLE test (content VARCHAR(65533));
-- 但实际更少,因为还要考虑字符集
CREATE TABLE test_utf8 (
c1 VARCHAR(65533) -- 报错!UTF8MB4 一个字符最多4字节,65533/4 不够
);
```
### 不同字符集的最大 VARCHAR
| 字符集 | 一个字符占字节 | VARCHAR 最大字符数 |
|--------|--------------|-----------------|
| LATIN1 | 1 | 65533 |
| GBK | 2 | 32766 |
| UTF8 | 3 | 21844 |
| UTF8MB4 | 4 | 16383 |
```sql
-- UTF8MB4 下 VARCHAR 最大 16383
CREATE TABLE test (
content VARCHAR(16383) -- 16383 × 4 = 65532 字节
);
```
## VARCHAR(255) vs VARCHAR(256)
就差一个字符,存储方式完全不同:
```sql
-- VARCHAR(255):长度前缀 1 字节
-- VARCHAR(256):长度前缀 2 字节
多出来的那个字节,每年多耗 1 字节存储空间,亿级数据量下也是一笔账。
为什么要用 VARCHAR(255)?
1. 历史习惯
早期 MySQL 的索引长度限制是 767 字节,UTF8 下 255 × 3 = 765,正好能建索引。后来这个限制放宽了(InnoDB 16KB 页),但习惯保留下来。
-- 767 字节限制下的最优解
CREATE INDEX idx_name ON user(name(255)); -- 255 × 3 = 765
-- 现在 InnoDB 支持更长的索引
-- MySQL 5.7+ 索引最大 3072 字节(767 × 4)
CREATE INDEX idx_name ON user(name(1024)); -- 1024 × 3 = 3072
2. 够用就行
大部分业务里,255 个字符够存大部分短文本:
- 用户名:20字符够用
-
- 邮箱:100字符够用
-
- 手机号:11字符
-
- 城市名:50字符够用
255 是个「安全值」,不会不够,也不浪费。
- 城市名:50字符够用
VARCHAR(255) 的坑
1. 没索引的 VARCHAR 查询慢
-- ❌ 存大文本但没索引
CREATE TABLE article (
title VARCHAR(255),
content TEXT -- 内容超过 255,存在 TEXT 里
);
-- ✅ 常用查询字段加索引
CREATE INDEX idx_title ON article(title);
2. VARCHAR 和 CHAR 的选择
-- CHAR(10):固定10字符,不足补空格
-- 存 "abc":实际存 "abc "(10字节)
-- VARCHAR(10):可变长度
-- 存 "abc":实际存 "abc"(1字节长度 + 3字节数据 = 4字节)
-- 选择原则:
-- - 长度固定(如邮编、手机号):用 CHAR
-- - 长度变化(如用户名、地址):用 VARCHAR
3. VARCHAR 在临时表里的问题
-- EXPLAIN 看到 Using temporary 说明用了临时表
EXPLAIN SELECT * FROM user WHERE name LIKE '%Tom%' ORDER BY created_at;
-- 大字段导致临时表存储在磁盘上,性能差
-- 解决:用前缀索引或覆盖索引
实战建议
| 场景 | 建议长度 | 说明 |
|---|---|---|
| 用户名 | VARCHAR(32) | 20个中文够用 |
| 邮箱 | VARCHAR(100) | 标准邮箱最多 320 字符,但实际 100 够 |
| 手机号 | CHAR(11) | 固定长度,用 CHAR |
| 密码(哈希后) | CHAR(64) | BCrypt 是 60 字符,其他哈希 64 字符 |
| 简介 | VARCHAR(200) | 中文100字够用 |
| 文章标题 | VARCHAR(200) | 标准博客标题 |
| 详细地址 | VARCHAR(255) | 够用 |
小结
| 问题 | 答案 |
|---|---|
| 为什么是 255? | 单字节字符串最大长度,够存大部分短文本 |
| VARCHAR(255) vs (256)? | 长度前缀不同,255 用 1 字节,256 用 2 字节 |
| 最大能存多少? | UTF8MB4 下最多 16383 字符 |
| 什么场景用? | 长度不固定的短文本 |
下次写表结构,别无脑 VARCHAR(255) 了,按实际需求选。
相关阅读:
- [MySQL 数据类型选择最佳实践]
-
- [MySQL 时间类型选择]
-
- [MySQL 索引底层 B+ 树原理]
更多推荐

所有评论(0)