一句话

选最小的、能装下你数据的类型。 类型小 = 索引小 = 内存命中率高 = 快。

一、整数类型

类型字节范围(无符号)用途
TINYINT10 ~ 255状态枚举、布尔
SMALLINT20 ~ 65535较小计数
MEDIUMINT30 ~ 1677w较少用
INT40 ~ 42亿大多数主键、ID
BIGINT80 ~ 1844亿亿雪花 ID、大表主键
1
2
3
4
-- ❌ 用户性别用 INT
gender INT
-- ✅ 用 TINYINT
gender TINYINT UNSIGNED COMMENT '0未知 1男 2女'

INT(11) 里的 11 不是长度!只是显示宽度(已废弃),实际仍是 4 字节。

二、字符串类型

类型长度适用
CHAR(n)固定 n 字符MD5、UUID、固定位手机号
VARCHAR(n)可变 ≤ n大多数字符串
TEXT (4 种)长文本文章正文,不要建普通索引
ENUM枚举不推荐,改字段难
JSON5.7+半结构化数据

CHAR vs VARCHAR

维度CHARVARCHAR
存储固定,不足补空格1-2 字节长度 + 实际内容
速度略快(无需算长度)略慢
空间浪费(固定占满)节省
适用长度真正固定长度变化

三、日期时间

类型字节范围时区
DATE31000-01-01 ~ 9999-12-31
TIME3-838:59:59 ~ 838:59:59
DATETIME81000 ~ 9999不存时区
TIMESTAMP41970 ~ 2038存 UTC,按 session 时区显示
YEAR11901 ~ 2155

DATETIME vs TIMESTAMP

1
2
3
4
5
-- TIMESTAMP:跨时区应用首选
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

-- DATETIME:明确不需要时区转换、超 2038 年
contract_end DATETIME

2038 问题:TIMESTAMP 上限 2038-01-19 03:14:07 UTC,长期合同/出生日期一定用 DATETIME。

四、浮点 vs 定点

类型精度用途
FLOAT (4) / DOUBLE (8)不精确科学计算、统计
DECIMAL(M, D)精确金额、汇率、价格
1
2
3
4
5
-- ❌ 用 FLOAT 存钱:0.1 + 0.2 ≠ 0.3
price FLOAT

-- ✅
price DECIMAL(10, 2) -- 最大 99999999.99

五、JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
profile JSON

-- 写入
INSERT INTO users (profile) VALUES ('{"city": "Taipei", "tags": ["dev"]}');

-- 查询
SELECT profile->>'$.city' FROM users;
SELECT * FROM users WHERE JSON_CONTAINS(profile->'$.tags', '"dev"');

-- 索引(虚拟列)
ALTER TABLE users ADD city VARCHAR(20)
AS (profile->>'$.city') STORED,
ADD INDEX idx_city(city);

注意:JSON 灵活但失去强 schema,能用普通列就别用 JSON。

六、设计经验

  1. 能 NOT NULL 就 NOT NULL —— NULL 让索引、统计、计算都更复杂
  2. 整数无符号 UNSIGNED —— 范围加倍、避免负数业务 bug
  3. 避免 ENUM —— 改值要 ALTER TABLE,用 TINYINT + 字典表
  4. TEXT/BLOB 单独存表 —— 主表行长可控
  5. 手机号用 VARCHAR —— +号、前导 0、国家码
  6. 金额绝不用 FLOAT —— 用 DECIMAL 或存”分”用 INT

速查表

想存的内容推荐类型
主键 IDINT UNSIGNED 或 BIGINT
性别/状态TINYINT UNSIGNED
用户名VARCHAR(64)
邮箱VARCHAR(255)
密码 hashCHAR(60) (bcrypt)
手机号VARCHAR(20)
金额DECIMAL(10,2)
时间戳TIMESTAMP(带时区)/ DATETIME
IP 地址INT UNSIGNED + INET_ATON(),或 VARBINARY(16)
大文本TEXT,单独表
半结构化JSON,慎用

参考