MySQL 表结构设计:忘记范式准则
前面几讲我虽然带你了解了数字类型、字符串、日期类型,以及非结构化的 JSON 类型,但也只是每条记录每个字段的选择。
而我们在对一张表进行设计时,还要遵守一些基本的原则,比如你经常听见的“范式准则”。但范式准则过于理论,在真实业务中,你不必严格遵守三范式的要求。而且有时为了性能考虑,你还可以进行反范式的设计,比如在数据仓库领域。这一讲我就会带你了解这些内容,希望你学完这一讲之后,能从更高一层的维度来看待 MySQL 数据库的表结构设计。
忘记范式准则
相信你在大学学习《数据库系统概论》时,肯定学习过关系数据库的设计规范,比如第一范式、第二范式、第三范式,BC 范式等,它们是《数据库系统概论》考试中重要的考点。
范式设计是非常重要的理论,是通过数学集合概念来推导范式的过程,在理论上,要求表结构设计必须至少满足三范式的要求。
由于完全是数据推导过程,范式理论非常枯燥,但你只要记住几个要点就能抓住其中的精髓:
-
一范式要求所有属性都是不可分的基本数据项;
-
二范式解决部分依赖;
-
三范式解决传递依赖。
虽然我已经提炼了范式设计的精髓,但要想真正理解范式设计,就要抛弃纯理论的范式设计准则,从业务角度出发,设计出符合范式准则要求的表结构。
工程上的表结构设计实战
真实的业务场景是工程实现,表结构设计做好以下几点就已经足够:
-
每张表一定要有一个主键(方法有自增主键设计、UUID 主键设计、业务自定义生成主键);
-
消除冗余数据存在的可能。
我想再次强调一下,你不用过于追求所谓的数据库范式准则,甚至有些时候,我们还会进行反范式的设计。
自增主键设计
主键用于唯一标识一行数据,所以一张表有主键,就已经直接满足一范式的要求了。在 01 讲的整型类型中,我提及可以使用 BIGINT 的自增类型作为主键,同时由于整型的自增性,数据库插入也是顺序的,性能较好。
但你要注意,使用 BIGINT 的自增类型作为主键的设计仅仅适合非核心业务表,比如告警表、日志表等。真正的核心业务表,一定不要用自增键做主键,主要有 6 个原因:
-
自增存在回溯问题;
-
自增值在服务器端产生,存在并发性能问题;
-
自增值做主键,只能在当前实例中保证唯一,不能保证全局唯一;
-
公开数据值,容易引发安全问题,例如知道地址http://www.example.com/User/10/,很容猜出 User 有 11、12 依次类推的值,容易引发数据泄露;
-
MGR(MySQL Group Replication) 可能引起的性能问题;
-
分布式架构设计问题。
自增存在回溯问题,我在 01 讲中已经讲到,如果你想让核心业务表用自增作为主键,MySQL 数据库版本应该尽可能升级到 8.0 版本。
又因为自增值是在 MySQL 服务端产生的值,需要有一把自增的 AI 锁保护,若这时有大量的插入请求,就可能存在自增引起的性能瓶颈。比如在 MySQL 数据库中,参数 innodb_autoinc_lock_mode 用于控制自增锁持有的时间。假设有一 SQL 语句,同时插入 3 条带有自增值的记录:
INSERT INTO ... VALUES (NULL,...),(NULL,...),(NULL,...);