很多人写表结构的时候,习惯性地写 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 是个「安全值」,不会不够,也不浪费。

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+ 树原理]
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐