数据类型与表设计
数据类型与表设计
正确选择数据类型和约束是数据库设计的第一步。选型不当会导致存储空间浪费、查询性能下降、数据完整性受损,甚至引发线上故障。本文系统梳理 MySQL 8.x 的核心数据类型,并讲解六种约束的含义、作用场景与设计原则。
数值类型
MySQL 提供精确数值和近似数值两大类。
精确数值:INT 系列
-- TINYINT:1 字节,-128 ~ 127(或 0~255 无符号)
CREATE TABLE t1 (age TINYINT UNSIGNED);
-- SMALLINT:2 字节,-32768 ~ 32767
CREATE TABLE t2 (score SMALLINT);
-- INT / INTEGER:4 字节,-21 亿 ~ 21 亿(日常使用最频繁)
CREATE TABLE t3 (user_id INT, view_count INT);
-- BIGINT:8 字节,适用超出 INT 范围的场景(如访问量、金额精确到分的乘积)
CREATE TABLE t4 (order_amount BIGINT); -- 存储单位:分原则:在满足范围的前提下,优先使用更小的类型。每节省 1 字节,索引体积更小,内存扫描更快。
精确数值:DECIMAL
用于存储精确小数(货币金额、科学计算),避免浮点误差:
-- DECIMAL(M, D):M = 总位数(含小数),D = 小数位数
-- 示例:DECIMAL(10,2) 表示最多 10 位数字,其中 2 位小数
-- 范围:-9999999.99 ~ 9999999.99
CREATE TABLE accounts (
balance DECIMAL(15, 2), -- 存储余额,最多 13 位整数 + 2 位小数
interest DECIMAL(5, 4), -- 利率,如 0.0355
exchange_rate DECIMAL(10, 6) -- 汇率,6 位小数保证精度
);近似数值:FLOAT 与 DOUBLE
-- FLOAT:4 字节,单精度浮点(不推荐存储精确值)
CREATE TABLE sensor_data (temperature FLOAT);
-- DOUBLE:8 字节,双精度浮点
CREATE TABLE math_constants (value DOUBLE);原则:永远不要用 FLOAT/DOUBLE 存储货币。它们是近似值,
0.1 + 0.2 = 0.30000000000000004在二进制浮点中是真实存在的误差。
无符号属性 UNSIGNED
-- 年龄不可能为负,使用 UNSIGNED
CREATE TABLE users (age TINYINT UNSIGNED);
-- 点赞数、访问量
CREATE TABLE articles (likes INT UNSIGNED, views BIGINT UNSIGNED);字符类型
CHAR 与 VARCHAR
这是最容易选错的类型组合:
-- CHAR(N):固定长度,不足部分用空格补齐。最大 255 字符。
-- 适用:国家代码(CN/USA)、性别(M/F)、状态码等**长度固定的字段**
CREATE TABLE countries (code CHAR(2), name VARCHAR(100));
-- VARCHAR(N):可变长度,只存储实际字符。最大 65535 字节(实际受行宽限制约 21653 字符)
-- 适用:用户名、邮箱、地址等**长度不确定的字段**
CREATE TABLE users (username VARCHAR(50), bio VARCHAR(500));| 特性 | CHAR | VARCHAR |
|---|---|---|
| 存储长度 | 固定 N | 实际字符数 + 1~2 字节长度前缀 |
| 性能 | 写入/读取略快(无需计算长度) | 略低(需解析长度前缀) |
| 空间 | 空白浪费(不足 N 时填充空格) | 紧凑 |
| 最大长度 | 255 | ~21653(字符集为 utf8mb4 时约 8000) |
字符集:utf8mb4(必须掌握)
MySQL 的 utf8 字符集仅支持 3 字节,无法存储 Emoji(需要 4 字节)。现代应用必须使用 utf8mb4:
-- 建库时指定字符集
CREATE DATABASE myapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 建表时指定
CREATE TABLE users (
username VARCHAR(50) CHARACTER SET utf8mb4,
bio TEXT CHARACTER SET utf8mb4
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_unicode_ci;建议:在
my.cnf中将默认字符集设为utf8mb4,一劳永逸。
TEXT 系列
用于存储超长文本,TEXT 不参与行大小计算(独立存储):
CREATE TABLE articles (
title VARCHAR(200), -- 标题有限长,用 VARCHAR
content TEXT, -- 文章正文,不限制长度
summary MEDIUMTEXT, -- 中等长度摘要(约 16MB)
raw_data LONGTEXT -- 超大文本,如 JSON、日志
);日期时间类型
CREATE TABLE events (
-- DATE:日期(1000-01-01 ~ 9999-12-31)
birthday DATE,
-- TIME:时间(-838:59:59 ~ 838:59:59)
work_hours TIME,
-- DATETIME:日期+时间,不受时区影响(存什么读什么)
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
-- TIMESTAMP:日期+时间,受时区影响(存 UTC,MySQL 自动转换)
-- 2038 年问题:最大值 2038-01-19 03:14:07
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
-- YEAR:年份(1901~2155 或 00~69/70~99)
birth_year YEAR
);原则:
- 用户注册时间、订单时间等业务时间,用
DATETIME- 自动记录变更时间(created_at / updated_at)用
TIMESTAMP- 不存具体时间只存日期用
DATE(如生日)- 有国际化需求时注意
DATETIMEvsTIMESTAMP的时区行为差异
约束(Constraint)
主键 PRIMARY KEY
唯一标识表中每一行的列(或列组合),不允许为空:
-- 单列主键
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50)
);
-- 多列复合主键(联合主键)
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id) -- 两列共同唯一
);自增 AUTO_INCREMENT
常与主键配合,自动生成连续整数 ID:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
INSERT INTO users (name) VALUES ('alice');
INSERT INTO users (name) VALUES ('bob');
-- id 自动生成:1, 2, ...NOT NULL 非空约束
-- 用户名不能为空
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL, -- 必填
email VARCHAR(100) NOT NULL
);UNIQUE 唯一约束
-- 邮箱必须唯一,但允许为空(空值可以有多个)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(100) UNIQUE
);
-- 多列组合唯一
CREATE TABLE user_roles (
user_id INT,
role_id INT,
UNIQUE (user_id, role_id) -- 同一用户不能有重复角色
);DEFAULT 默认值
CREATE TABLE articles (
title VARCHAR(200) NOT NULL,
published BOOLEAN DEFAULT FALSE, -- 默认为草稿
views INT DEFAULT 0, -- 默认阅读量为 0
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);外键 FOREIGN KEY
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
total DECIMAL(10, 2),
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE -- 级联删除:删除用户时其订单一并删除
ON UPDATE CASCADE -- 级联更新:更新用户 ID 时同步更新订单
);外键约束的代价:每次 INSERT/UPDATE/DELETE 外键表时,MySQL 需要检查参照完整性,对高并发写入场景会产生额外锁竞争。现代架构中,也有不少团队选择在应用层(代码中)保证外键逻辑。
完整建表示例
整合以上知识点:
CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET=utf8mb4;
USE shop;
CREATE TABLE users (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
password_hash CHAR(60) NOT NULL, -- bcrypt 哈希固定 60 字符
age TINYINT UNSIGNED,
status TINYINT UNSIGNED DEFAULT 1, -- 1=活跃 0=禁用
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE (email),
INDEX (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;ENGINE=InnoDB:MySQL 8.x 的默认存储引擎,支持事务、行级锁、外键,是生产环境的必选。
总结
数据类型选择的核心原则:
- 数值:能用 TINYINT 不必用 INT;货币必用
DECIMAL - 字符串:长度固定用
CHAR,不确定用VARCHAR,超长用TEXT;始终使用utf8mb4 - 日期:业务时间用
DATETIME,自动时间戳用TIMESTAMP - 约束:主键必填、外键慎用、非空和唯一按业务需求添加
下一篇文章我们将学习 条件过滤与聚合查询,掌握 WHERE、LIKE、GROUP BY、HAVING 等数据处理核心技巧。
评论
Written by
AI-Writer
Related Articles
MySQL 安装与配置
在 macOS、Linux、Windows 上安装 MySQL 8.x、启动服务、配置连接,并介绍常用客户端工具 MySQL Workbench、DBeaver 与命令行 CLI 的使用方法
Read More