网站首页 > 教程文章 正文
1.设计表时包含这些通用字段
通常,一个表应包含以下字段:
- id:主键。每个表都必须有一个主键 — 没有例外。
- create_time:创建时间 — 必须包含。
- modified_time:最后修改时间 — 必须包含。每当记录被更新时,这个字段应该被更新。
- version:记录的版本号,通常用于乐观锁 — 可选。
- modifier:最后修改记录的人 — 可选。
- creator:创建记录的人 — 可选。
2.每个字段都应该有注释,尤其是枚举类型
在设计表时,每个字段都应该包含注释。这对于使用枚举的字段尤为重要 — 所有枚举值都应该在注释中列出。如果以后发生更改,也应该在注释中反映出来。
坏例子:
CREATE TABLE order_tab (
id INT AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT UNIQUE,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
payment_status VARCHAR(20) DEFAULT 'not_paid',
version INT DEFAULT 0,
created_time DATETIME,
updated_time DATETIME,
creator VARCHAR(255),
modifier VARCHAR(255)
);
好例子:
CREATE TABLE order_tab (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '订单项的唯一标识符,自动递增主键',
order_id BIGINT UNIQUE COMMENT '订单的全局唯一标识符',
user_id BIGINT NOT NULL COMMENT '用户的唯一标识符,与用户表关联',
total_amount DECIMAL(10, 2) NOT NULL COMMENT '总订单金额,精确到小数点后两位',
status VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '订单状态,例如 PENDING, COMPLETED 等',
payment_status VARCHAR(20) DEFAULT 'not_paid' COMMENT '支付状态,例如 not_paid, paid 等',
version INT DEFAULT 0 COMMENT '用于并发控制的乐观锁版本号',
created_time DATETIME COMMENT '订单创建时间戳',
updated_time DATETIME COMMENT '最后更新时间戳',
creator VARCHAR(255) COMMENT '订单创建者 — 通常是用户或系统的用户名',
modifier VARCHAR(255) COMMENT '最后修改订单的人或系统'
);
3. 命名规范
为表名、字段名、索引名等使用清晰一致的命名。良好的命名可以提高可读性和理解性。
例如,避免使用以下名称:
- acc_no, 1_acc_no(坏例子)
相反,使用:
- account_no, account_number(好例子)
其他规则:
- 表和字段名应使用小写字母或数字。
- 不要以数字开头。
- 避免使用缩写。
- 索引命名规范:
- 主键:pk_<字段名>
- 唯一索引:uk_<字段名>
- 普通索引:idx_<字段名>
4.选择合适的字段类型
在设计表时,选择最合适的字段类型:
- 合适数据类型以节省存储空间 — 例如,按顺序优先选择 tinyint、smallint、int、bigint。
- 对于货币值,使用 decimal 而不是 float 或 double。
- 如果字符串长度是固定,使用 char。
- 对于可变长度字符串,使用 varchar,但长度应保持在 5000 以下。
- 对于非常大的值,考虑使用 text 并将其存储在与主表关联的单独表中。
- 表中所有 varchar 字段的总长度不得超过 65535 字节。如果需要,使用 TEXT 或 LONGTEXT 类型。
5.设计合理的主键
避免将主键与业务逻辑绑定。例如,不建议使用用户 ID(即使它是唯一的)作为主键。相反,使用一个无意义但唯一的标识符,例如:
- 一个 UUID,
- 一个自动递增的主键,
- 一个由雪花算法生成的主键。
6.选择合适的字段长度
让我先问你一个问题:在数据库中,字段长度表示字符长度还是字节长度?
在 MySQL 中:
- varchar 和 char 指定字符长度。
- 其他类型通常指定字节长度。
例如:
- char(10) 表示 10 个字符。
- bigint(4) 指显示宽度(不是存储大小),但 bigint 总是占用 8 个字节。
在设计表时,仔细考虑字段长度。例如,对于预期长度在 5 到 20 个字符之间的用户名字段,你可以将其定义为 username varchar(32)。
提示:字段长度通常最好设置为 2 的幂次方(即,2)。
7.优先选择逻辑删除而非物理删除
物理删除:数据从磁盘上永久删除,释放存储空间。
逻辑删除:添加一个字段(如 is_deleted)来标记数据为已删除。
物理删除的示例:
DELETE FROM account_info_tab WHERE account_no = '666';
逻辑删除的示例:
UPDATE account_info_tab SET is_deleted = 1 WHERE account_no = '666';
为什么优先选择逻辑删除?
- 物理删除使得数据恢复变得困难。
- 自动递增的主键变得不连续。
- 对于核心业务表,最好更新状态字段而不是物理删除记录。
8.避免单表字段过多
在设计表时,尽量限制字段数量 — 通常不超过 20 个。
字段过多可能导致:
- 行尺寸过大,
- 查询性能差。
如果业务逻辑需要许多字段,考虑将大表拆分为具有相同主键的小表。
当一个表有大量字段时,可以将其拆分为:
- 一个“查询条件”表(用于快速过滤),
- 一个“详细”表(用于完整内容),以提高性能。
9.尽量使用 NOT NULL
除非有特定原因,建议将字段定义为 NOT NULL。
为什么?
- 防止空指针问题。
- NULL 占用额外的存储空间。
- 与 NULL 的比较更复杂,阻碍查询优化。
- NULL 值可能导致索引失败。
- 如果可以安全地将字段默认为一个空字符串或常量,你应该将其定义为 NOT NULL。
10.评估哪些字段需要索引
首先,评估你的数据集的大小。如果一个表只有几百行,可能不需要索引。
一般来说,如果一个字段经常用于查询条件,它应该有一个索引。但索引不应被过度使用:
- 避免创建过多的索引 — 每个表保持在 5 个或更少。
- 过多的索引会减慢插入和更新操作。
- 不要为低基数的字段(例如,性别)创建索引。
- 注意可能导致索引失败的情况,例如在索引字段上使用内置的 MySQL 函数。
- 为了减少索引数量,考虑复合(多列)索引。
- 使用覆盖索引技术,并遵循最左前缀规则。
用户表的示例:
CREATE TABLE user_info_tab (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`create_time` datetime NOT NULL,
`modifed_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
由于你可能会按 user_id 或 name 查询,并且 user_id 是唯一的,你可以这样定义索引:
CREATE TABLE user_info_tab (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
`create_time` datetime NOT NULL,
`modifed_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`) USING BTREE,
UNIQUE KEY un_user_id (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
11. 避免使用 MySQL 保留字
如果数据库名、表名或字段名包含保留字,在 SQL 语句中必须用反引号(`)将其括起来。这使得编写 SQL 语句变得复杂,并增加了出错的风险,特别是在脚本编写或与 shell 变量一起使用时。
因此,避免使用 MySQL 保留字,如 select、interval、desc 等。
12.优先选择 InnoDB 存储引擎
在创建表时,你必须选择一个存储引擎。一般来说,除非你的读写比例小于 1%,在这种情况下可以考虑使用 MyISAM,否则应优先选择 InnoDB。
13.选择合适的时间类型
在设计表时,我们通常会包含诸如 create_time、modified_time 等与时间相关的通用字段。那么应该使用哪种 MySQL 时间类型呢?
主要选项包括:
- date:以 yyyy-mm-dd 格式存储日期值。范围:1000-01-01 到 9999-12-31。大小:3 字节。
- time:以 hh:mm:ss 格式存储时间值。范围:-838:59:59 到 838:59:59。大小:3 字节。
- datetime:以 yyyy-mm-dd hh:mm:ss 格式存储日期和时间。范围:1000-01-01 00:00:00 到 9999-12-31 23:59:59。大小:8 字节。不依赖时区。
- timestamp:以时间戳(yyyymmddhhmmss)格式存储日期和时间。范围:1970-01-01 00:00:01 到 2038-01-19 03:14:07。大小:4 字节。依赖时区。
- year:以 yyyy 格式存储年份值。范围:1901 到 2155。大小:1 字节。
建议:优先使用 datetime 类型来存储日期和时间,因为它具有更大的范围并且不依赖时区。
14.安全考虑
- 数据加密:敏感信息(如用户密码)应以加密格式存储。
- 数据脱敏:对于个人身份识别信息(PII),如电话号码或电子邮件地址,数据脱敏以更好地保护隐私和合规性。
原文:
https://www.yuque.com/fengjutian/eyzi2i/muqhrehwm8e3ac3w?singleDoc# 《设计 MySQL 表的 14 条原则》
猜你喜欢
- 2025-04-26 MySQL与SQLite:如何通过DESCRIBE命令查看表结构并解决常见问题
- 2025-04-26 使用MySQL全文索引,我让女同事的代码快了1000倍
- 2025-04-26 mysql 替换某一个字段中的字符串
- 2025-04-26 mysql数据库——约束
- 2025-04-26 Mysql数据库替换整张表中某字段中指定的部分字符
- 2025-04-26 对线面试官:MySQL 给数据表增加一列,一定会锁表吗?
- 2025-04-26 如何确保mysql的alter语句不锁表
- 2025-04-26 MySQL字段内容拆分及合并
- 2025-04-26 MySQL笔试题-INSERT SELECT批量插入
- 2025-04-26 mysql 之json字段详解(多层复杂检索)
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- md5 sha1 (32)
- mybatis plus page (35)
- semaphore 使用详解 (32)
- update from 语句 (32)
- vue @scroll (38)
- 堆栈区别 (33)
- 在线子域名爆破 (32)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)