MySQL表结构的一些设计经验分享

我们在对一张表进行设计时,还要遵守一些基本的原则,比如经常听见的“范式准则”。但范式准则过于理论,在真实业务中,不必严格遵守三范式的要求。而且有时为了性能考虑,还可以进行反范式的设计,比如在数据仓库领域。这篇文章我们来分享些表设计的一些经验。

一、忘记范式准则

相信在大学学习《数据库系统概论》时,肯定学习过关系数据库的设计规范,比如第一范式、第二范式、第三范式,BC 范式等,它们是《数据库系统概论》考试中重要的考点。

范式设计是非常重要的理论,是通过数学集合概念来推导范式的过程,在理论上,要求表结构设计必须至少满足三范式的要求。

  • 一范式要求所有属性都是不可分的基本数据项;

  • 二范式解决部分依赖;

  • 三范式解决传递依赖。

要想真正理解范式设计,就要抛弃纯理论的范式设计准则,从业务角度出发,设计出符合范式准则要求的表结构

二、工程上的表结构设计实战

真实的业务场景是工程实现,表结构设计做好以下几点就已经足够:

  • 每张表一定要有一个主键(方法有自增主键设计、UUID 主键设计、业务自定义生成主键);

  • 消除冗余数据存在的可能。

三、自增主键设计

主键用于唯一标识一行数据,所以一张表有主键,就已经直接满足一范式的要求了。在前面文章中我们聊过可以使用 BIGINT 的自增类型作为主键,同时由于整型的自增性,数据库插入也是顺序的,性能较好。

但要注意,使用 BIGINT 的自增类型作为主键的设计仅仅适合非核心业务表,比如告警表、日志表等。真正的核心业务表,一定不要用自增键做主键,主要有 6 个原因:

  • 自增存在回溯问题;

  • 自增值在服务器端产生,存在并发性能问题;

  • 自增值做主键,只能在当前实例中保证唯一,不能保证全局唯一;

  • 公开数据值,容易引发安全问题,例如知道地址http://www.example.com/User/10/,很容猜出 User 有 11、12 依次类推的值,容易引发数据泄露;

  • MGR(MySQL Group Replication) 可能引起的性能问题;

  • 分布式架构设计问题。

如果你想让核心业务表用自增作为主键,MySQL 数据库版本应该尽可能升级到 8.0 版本。

四、UUID主键设计

UUID(Universally Unique Identifier)代表全局唯一标识 ID。显然,由于全局唯一性,可以把它用来作为数据库的主键。

MySQL 数据库遵循 DRFC 4122 命名空间版本定义的 Version 1规范,可以通过函数 UUID自动生成36字节字符。如:

mysql> SELECT UUID();

+--------------------------------------+

| UUID()                               |

+--------------------------------------+

| e0ea12d4-6473-11eb-943c-00155dbaa39d |

+--------------------------------------+

根据 Version 1的规范,MySQL中的 UUID 由以下几个部分组成:

UUID = 时间低(4字节)- 时间中高+版本(4字节)- 时钟序列 - MAC地址

前 8 个字节中,60 位用于存储时间,4 位用于 UUID 的版本号,其中时间是从 1582-10-15 00:00:00.00 到现在的100ns 的计数。

五、业务自定义生成主键

UUID 虽好,但是在分布式数据库场景下,主键还需要加入一些额外的信息,这样才能保证后续二级索引的查询效率(具体这部分内容将在后面的分布式章节中进行介绍)。只需要牢记:分布式数据库架构,仅用 UUID 做主键依然是不够的。 所以,对于分布式架构的核心业务表,推荐类似如下的设计,比如:

PK = 时间字段 + 随机码(可选) + 业务信息1 + 业务信息2 ......

电商业务中,订单表是其最为核心的表之一,大家可以先打开淘宝 App,查询下自己的订单号,可以查到类似如下的订单信息:

订单号显然是订单表的主键,但如果以为订单号是自增整型,那就大错特错了。如果仔细观察的话,可以发现图中所有订单号的后 6 位都是相同的,都为308113:

1550672064762308113

1481195847180308113

1431156171142308113

1431146631521308113

淘宝订单号的最后 6 位是用户 ID 相关信息,前 14 位是时间相关字段,这样能保证插入的自增性,又能同时保留业务的相关信息作为后期的分布式查询。

六、消除冗余

消除冗余也是范式的要求,解决部分依赖和传递依赖,本质就是尽可能减少冗余数据。

所以,在进行表结构设计时,数据只需存放在一个地方,其他表要使用,通过主键关联存储即可。比如订单表中需要存放订单对应的用户信息,则保存用户 ID 即可:

CREATE TABLE Orders (

  order_id VARCHRA(20),

  user_id  BINARY(16),

  order_date datetime,

  last_modify_date datetime

  ...

  PRIMARY KEY(order_id),

  KEY(user_id,order_date)

  KEY(order_date),

  KEY(last_modify_date)

)

当然了,无论是自增主键设计、UUID主键设计、业务自定义生成主键、还是消除冗余,本质上都是遵循了范式准则。但是在一些其他业务场景下,也存在反范式设计的情况。

七、反范式设计

通常我们会在 OLAP 数据分析场景中使用反范式设计,但随着 JSON 数据类型的普及,MySQL 在线业务也可以进行反范式的设计。

文章将持续更新,欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱娃哈哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值