一文通关 MySQL 数据类型,打好高性能数据库的第一战!
数据类型选错,是MySQL性能杀手Top3之一(其他两个是索引乱加 + SELECT * 成习惯)。
2026年MySQL主流仍是8.4 LTS系列(创新分支已到9.x,但生产稳扎稳打还是8.4),数据类型本身变化不大,但“最小合适 + 理解存储代价 + 索引友好” 这三条原则比任何时候都更重要。
我们直接用最务实的结构来过一遍:分类 + 范围 + 存储代价 + 推荐场景 + 常见雷区。
1. 数值类型(最常用、最影响性能的一类)
| 类型 | 占用字节 | 有符号范围 | 无符号范围 | 推荐场景(2026主流) | 常见坑 / 注意点 |
|---|---|---|---|---|---|
| TINYINT | 1 | -128 ~ 127 | 0 ~ 255 | 年龄、状态码、性别、布尔(0/1) | 别用TINYINT存“可能超过255”的东西 |
| SMALLINT | 2 | -32,768 ~ 32,767 | 0 ~ 65,535 | 城市ID、小订单量、库存少量 | — |
| MEDIUMINT | 3 | -8,388,608 ~ 8,388,607 | 0 ~ 16,777,215 | 中等基数ID(如文章ID早期阶段) | 很少用,跳过直接用INT |
| INT / INTEGER | 4 | -2^31 ~ 2^31-1 | 0 ~ 2^32-1 | 用户ID、订单ID、商品ID(绝大多数业务首选) | 主键/外键默认用INT UNSIGNED |
| BIGINT | 8 | -2^63 ~ 2^63-1 | 0 ~ 2^64-1 | 雪花ID、支付流水号、点赞数亿级、时间戳(ms) | 别滥用,4字节INT够用就别上8字节 |
| DECIMAL / NUMERIC | 变长 | 精度由M,D决定 | — | 金额、汇率、科学计算(绝对不能用FLOAT/DOUBLE) | DECIMAL(18,4) 常见电商金额 |
| FLOAT / DOUBLE | 4 / 8 | 约6/15位有效数字 | — | 科学计算、坐标(不要求绝对精确) | 生产禁用用于金融/金额,精度丢失 |
2026核心建议:
- 主键/外键/高频WHERE/JOIN字段 → INT UNSIGNED 或 BIGINT UNSIGNED(自增/雪花)
- 年龄/状态/枚举值 → TINYINT UNSIGNED
- 钱相关 → DECIMAL(15,2) ~ DECIMAL(18,4)(视业务最大值)
- 永远别用FLOAT/DOUBLE存钱(哪怕你加了四舍五入也容易出1分钱bug)
2. 字符串类型(空间 & 索引开销大户)
| 类型 | 存储方式 | 最大长度 | 适用场景 | 性能建议 & 雷区 |
|---|---|---|---|---|
| CHAR(n) | 固定长度,补空格 | 0~255 | 固定长度码(如身份证前6位、省份码、性别M/F) | 适合真正固定长;短数据浪费空间 |
| VARCHAR(n) | 变长 + 1~2字节长度前缀 | 0~65,535 | 绝大多数文本字段(姓名、地址、标题) | 主流首选;n设真实最大值,别习惯255/500 |
| TINYTEXT | 变长 | 255 | 极短文本 | 很少用 |
| TEXT | 变长 | 65,535 | 文章正文、评论(较短) | 不能建普通索引(前缀索引可) |
| MEDIUMTEXT | 变长 | 16MB | 长文章、富文本 | — |
| LONGTEXT | 变长 | 4GB | 超大内容(如日志、爬虫页面) | 慎用,IO代价高 |
关键避坑:
- VARCHAR(255) 是坏习惯 → 改成VARCHAR(50)/VARCHAR(100)/VARCHAR(191)(191是utf8mb4单列索引最大字节限制)
- 带emoji/全球字符 → 必须用utf8mb4字符集,别用utf8(utf8只支持3字节,emoji4字节会报错)
- 超过500字符的文本字段 → 考虑放OSS + 只存URL
3. 日期 & 时间类型(排序 & 范围查询最友好)
| 类型 | 占用字节 | 格式 / 范围 | 推荐场景 | 注意事项 & 推荐写法 |
|---|---|---|---|---|
| DATE | 3 | ‘1000-01-01’ ~ ‘9999-12-31’ | 生日、注册日 | — |
| DATETIME | 5~8 | ‘1000-01-01 00:00:00’ ~ ‘9999-12-31 …’ | 创建时间、更新时间、订单时间(主流) | DATETIME DEFAULT CURRENT_TIMESTAMP |
| TIMESTAMP | 4 | ‘1970-01-01 00:00:01’ UTC ~ 2038 | 自动更新时间戳(旧项目多见) | 2038年问题;MySQL 8.0+支持到2106 |
| TIME | 3 | ‘-838:59:59’ ~ ‘838:59:59’ | 时长、营业时间 | — |
| YEAR | 1 | 1901 ~ 2155 | 出生年份 | 极少用 |
2026推荐组合:
created_at DATETIME(0) DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME(0) DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at DATETIME(0) DEFAULT NULL COMMENT '软删除'
4. 其他常用 / 新兴类型
- JSON(MySQL 5.7+):文档存储、配置、扩展字段。支持JSON路径索引、函数(JSON_EXTRACT等)
- 推荐:热点读多 → 抽成结构化字段;偶尔读 → JSON
- ENUM / SET:空间省,但改值要ALTER TABLE,慎用(2026主流建议用TINYINT + 代码映射代替)
- BOOLEAN:实际是TINYINT(1),0/1存true/false
- VECTOR(MySQL 9.0+创新分支):AI嵌入向量(embedding),支持距离计算(欧氏/余弦等)
- 生产用得少,HeatWave或专用向量DB更常见
5. 一张终极选择速查表(直接抄)
| 业务字段 | 推荐类型 | 为什么 / 替代方案 |
|---|---|---|
| 主键ID | BIGINT UNSIGNED | 雪花ID安全;或INT UNSIGNED(小系统) |
| 用户名/昵称 | VARCHAR(30)~VARCHAR(60) | utf8mb4 |
| 手机号 | VARCHAR(20) | 考虑+86等前缀 |
| 金额 | DECIMAL(12,2) 或 DECIMAL(18,4) | 精确无丢失 |
| 创建/更新时间 | DATETIME(0) | 支持毫秒用DATETIME(3) |
| 状态 | TINYINT UNSIGNED | 0=待支付 1=已支付 … |
| 性别 | TINYINT(1) 或 ENUM(‘男’,’女’,’其他’) | TINYINT更灵活 |
| IP地址 | VARCHAR(45) | 支持IPv6 |
| 文章内容 | MEDIUMTEXT 或 TEXT | 长文本放外部存储 |
6. 性能第一定律(背下来)
“越小越好,但别溢出” + “索引友好” + “utf8mb4统一”
- 选最小能装下的类型 → 少占空间 → 索引更小 → 内存命中更高 → IO更少
- VARCHAR(n) 的n要真实业务最大值(别255默认)
- 所有表统一utf8mb4_unicode_520_ci(或 utf8mb4_0900_ai_ci)
- 金额/坐标/科学计数 → 坚决不用FLOAT/DOUBLE
- 主键别用UUID(乱序插入页分裂),用自增或有序雪花
你现在建表时最纠结哪个字段的类型?
或者你有一个具体的业务表(比如订单表、用户表),贴出当前建表语句,我可以帮你直接优化数据类型 + 指出潜在性能雷。