数据库设计范式与策略思考 | 青训营笔记

202 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记

数据库是Web业务中一个非常重要的组件,在项目的生命周期中对数据库进行持续的维护和优化对业务的顺畅运行,数据的汇总分析都有很大意义。“九层之台,起于累土”,优秀的数据库开发与维护工作始于设计阶段的预见和规划,本篇笔记就从数据库设计范式与策略出发,思考一些良好的设计习惯。

三范式与BC范式

典型的数据库三大范式(1NF,2NF,3NF)分别满足字段原子性(无多值)、无部分依赖、无传递依赖。在此基础上,还有更严格的BCNF,在关系代数中,BCNF表现为:

具有函数依赖集FF的关系模式RR属于BCNF的条件是,对所有F的闭包中形如 XYX \rightarrow Y,则下面的两个条件至少有一个成立:1. XYX \rightarrow Y是非平凡函数依赖. 2. XXRR的一个超键

遵循以上范式设计的数据表结构能够避免冗余,为业务中的数据更新效率,后续数据库的扩展能力,聚合的高效性,数据的有效性等提供了保障。

在本次青训营抖音项目的大作业中,我们小队起初就设计了遵循BCNF范式的数据表结构。然而,在实际业务中,为了操作的高效,往往会容忍一些字段依赖的冗余性。例如下表中的ThumbCount和CommentCount字段,实际是聚合值,可以由对其他表的查询计算得出,但在更新时同步维护这些聚合值就能在查询时以O(1)O(1)的复杂度获取聚合值,对于只需要聚合值的场合可以大大加速。

type DbVideo struct {
    Id           int64  `gorm:"primary_key;AUTO_INCREMENT"`
    Title        string `gorm:"index:VdeioTitle;not null"` 
    CreateUid    int64  `json:"create_uid" gorm:"not null"`
    Timestamp    string `json:"timestamp" gorm:"not null"`
    PlayUrl      string `json:"play_url" gorm:"not null"`
    CoverUrl     string `json:"cover_url" gorm:"not null"`
    ThumbCount   int64  `json:"thumb_count" gorm:"default:0"`
    CommentCount int64  `json:"comment_count" gorm:"default:0"`
}

哈希与负载均衡

在分布式数仓场景中,我们往往会根据字段的值范围进行负载均衡,分配到不同的存储节点上。然而诸如时间戳这类很容易存在局部爆发的字段,很容易造成数据存储的倾斜问题,此时在设计时对字段进行哈希或其他操作,可以有效解决数据倾斜问题,实现更鲁棒的负载均衡

查询加速

对于比较稀疏的字段(新建用户名,是否点赞)等,查询结果通常是不存在,对于这种大部分查询都返回空值的字段/数据库,每次都进行全表扫描则比较浪费性能。解决方案有两类,一类是采用布隆过滤器进行快速的判空,另一类可以参考DNS中的负面缓存(Negative Cache)机制,对无效查询也进行缓存,但也要注意更新时间粒度,尽量避免一致性冲突。

本篇笔记简单介绍了青训营期间思考的三条设计习惯,学海无涯,在后续的工作学习中还会收集更多的思考。