前言

最近有不少前端和测试转Go的敌人私信我:如何做好表结构设计?

大家关怀的问题阳哥必须整理出来,心愿对大家有帮忙。

先说论断

这篇文章介绍了设计数据库表构造应该思考的4个方面,还有优雅设计的6个准则,举了一个例子分享了我的设计思路,为了进步性能咱们也要从多方面思考缓存问题。

播种最大的还是和大家的交换探讨,总结一下:

  1. 首先,肯定要先搞清楚业务需要。比方我的例子中,如果不须要灵便设置,齐全能够写到配置文件中,并不需要独自设计外键。主表中间接保留各种筛选标签名称(留神保护的问题,要思考到数据一致性)
  2. 数据库表结构设计肯定思考数据量和并发量,我的例子中如果数据量小,能够适当做冗余设计,升高业务复杂度。

4个方面

设计数据库表构造须要思考到以下4个方面:

  1. 数据库范式:通常状况下,咱们心愿表的数据合乎某种范式,这能够保证数据的完整性和一致性。例如,第一范式要求表的每个属性都是原子性的,第二范式要求每个非主键属性齐全依赖于主键,第三范式要求每个非主键属性不依赖于其余非主键属性。
  2. 实体关系模型(ER模型):咱们须要先依据理论状况画出实体关系模型,而后再将其转化为数据库表构造。实体关系模型通常包含实体、属性、关系等因素,咱们须要将它们转化为表的模式。
  3. 数据库性能:咱们须要思考到数据库的性能问题,包含表的大小、索引的应用、查问语句的优化等。
  4. 数据库安全:咱们须要思考到数据库的平安问题,包含表的权限、用户角色的设置等。

设计准则

在设计数据库表构造时,能够参考以下几个优雅的设计准则:

  1. 简单明了:表构造应该简单明了,防止适度复杂化。
  2. 一致性:表构造应该放弃一致性,例如命名标准、数据类型等。
  3. 规范化:尽可能将表规范化,防止数据冗余和不一致性。
  4. 性能:表构造应该思考到性能问题,例如应用适当的索引、防止全表扫描等。
  5. 平安:表构造应该思考到平安问题,例如正当设置权限、防止SQL注入等。
  6. 扩展性:表构造应该具备肯定的扩展性,例如预留字段、可扩大的关系等。

最初,须要揭示的是,优雅的数据库表构造须要在实践中一直迭代和优化,一直满足理论需要和新的挑战。

上面举个示例让大家更好的了解如何设计表构造,如何引入内存,有哪些优化思路:

问题形容

如上图所示,红框中的视频筛选标签,应该怎么设计数据库表构造?除了前台筛选,还想反对在治理后盾灵便配置这些筛选标签。

这是一个很好的利用场景,大家能够先本人想一下。不要焦急看我的计划。

需要剖析

  1. 能够依据红框的标签筛选视频
  2. 其中综合标签比拟非凡,和类型、地区、年份、演员等不一样
  3. 综合是依据业务逻辑取值,并不需要入库
  4. 类型、地区、年份、演员等须要入库
  5. 设计表构造时要思考到:
  6. 不便获取标签信息,不便把标签信息缓存解决
  7. 不便依据标签筛选视频,不便咱们写后续的业务逻辑

设计思路

  1. 综合标签能够写到配置文件中(或者写在前端),这些信息不须要灵便配置,所以不须要保留到数据库中
  2. 类型、地区、年份、演员都设计独自的表
  3. 视频表中设计标签表的外键,不便视频列表筛选取值
  4. 标签信息写入缓存,进步接口响应速度
  5. 类型、地区、年份、演员表也要反对对数据排序,不便前期治理保护

表结构设计

视频表

字段正文
id视频主键id
type_id类型表外键id
area_id地区表外键id
year_id年份外键id
actor_id演员外键id

其余和视频间接相干的字段(比方名称)我就省略不写了

类型表

字段正文
id类型主键id
name类型名称
sort排序字段

地区表

字段正文
id类型主键id
name类型名称
sort排序字段

年份表

字段正文
id类型主键id
name类型名称
sort排序字段

原以为年份字段不须要排序,要么是年份正序排列,要么是年份倒序排列,所以不须要sort字段。

认真看了看需要,还有“10年代”还是须要灵便配置的呀~

演员表

字段正文
id类型主键id
name类型名称
sort排序字段

表结构设计完了,别忘了缓存

缓存策略

首先这些不会频繁更新的筛选条件倡议应用缓存:

  1. 比拟罕用的就是redis缓存
  2. 再进阶一点,如果你应用docker,能够把这些配置信息写入docker容器所在物理机的内存中,而不必申请其余节点的redis,进一步升高网络传输带来的耗时损耗
  3. 筛选条件这类配置信息,客户端和服务端能够约定一个更新缓存的机制,客户端间接缓存配置信息,进一步提高性能

列表数据主动缓存

目前很多框架都是反对主动缓存解决的,比方goframe和go-zero

goframe

能够应用ORM链式操作-查问缓存

示例代码:

package mainimport (    "time"    "github.com/gogf/gf/v2/database/gdb"    "github.com/gogf/gf/v2/frame/g"    "github.com/gogf/gf/v2/os/gctx")func main() {    var (        db  = g.DB()        ctx = gctx.New()    )    // 开启调试模式,以便于记录所有执行的SQL    db.SetDebug(true)    // 写入测试数据    _, err := g.Model("user").Ctx(ctx).Data(g.Map{        "name": "xxx",        "site": "https://xxx.org",    }).Insert()    // 执行2次查问并将查问后果缓存1小时,并可执行缓存名称(可选)    for i := 0; i < 2; i++ {        r, _ := g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{            Duration: time.Hour,            Name:     "vip-user",            Force:    false,        }).Where("uid", 1).One()        g.Log().Debug(ctx, r.Map())    }    // 执行更新操作,并清理指定名称的查问缓存    _, err = g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{        Duration: -1,        Name:     "vip-user",        Force:    false,    }).Data(gdb.Map{"name": "smith"}).Where("uid", 1).Update()    if err != nil {        g.Log().Fatal(ctx, err)    }    // 再次执行查问,启用查问缓存个性    r, _ := g.Model("user").Ctx(ctx).Cache(gdb.CacheOption{        Duration: time.Hour,        Name:     "vip-user",        Force:    false,    }).Where("uid", 1).One()    g.Log().Debug(ctx, r.Map())}

go-zero

DB缓存机制

go-zero缓存设计之长久层缓存

官网都做了具体的介绍,不作为本文的重点。

探讨

这篇文章首发在我的公众号《如何做好表结构设计?》,引起了大家的探讨。

也和大家分享一下:

Q1 冗余设计和一致性问题

发问: 一个表里做了这么多外键,如果我要查各自的名称,势必要关联4张表,对于这种存在多外键关联的这种表,要不要做冗余呢(间接在主表里冗余各自的名称字段)?要是保障一致性的话,就势必会影响性能,如果做冗余的话,又无奈保障一致性

答复:

你看文章的上下文应该晓得,文章想解决的是视频列表筛选问题。

你提到的这个场景是在视频详情信息中,如果要展现这些外键的名称怎么设计更好。

我的倡议是这样的:

  1. 依据需要能够做适当冗余,比方你的主表信息量不大,配置信息批改后同步批改冗余字段的老本并不高。
  2. 或者像我文章中写的不做冗余设计,然而会把外键信息缓存,业务查问从缓存中取值。
  3. 或者将视频详情的查问后果整体进行缓存

还是看具体需要,如果这些筛选信息不变动或者不须要手工治理,甚至不须要设计表,间接写死在代码的配置文件中也能够。进一步升高DB压力,进步性能。

Q2 why设计外键?

发问:为什么要设计外键关联?间接写到视频表中不就行了?这么设计的意义在哪里?

答复:

  1. 关键问题是想解决治理后盾灵便配置
  2. 如果没有这个需要,咱们能够间接把筛选条件以配置文件的形式写死在程序中,升高复杂度。
  3. 站在我的角度:这个性能的筛选条件变动并不会很大,所以很懂你的意思。也倡议像我2.中的计划去做,去和产品经理拉扯喽~

总结

这篇文章介绍了设计数据库表构造应该思考的4个方面,还有优雅设计的6个准则,举了一个例子分享了我的设计思路,为了进步性能咱们也要从多方面思考缓存问题。

播种最大的还是和大家的交换探讨,总结一下:

  1. 首先,肯定要先搞清楚业务需要。比方我的例子中,如果不须要灵便设置,齐全能够写到配置文件中,并不需要独自设计外键。主表中间接保留各种筛选标签名称(留神保护的问题,要思考到数据一致性)
  2. 数据库表结构设计肯定思考数据量和并发量,我的例子中如果数据量小,能够适当做冗余设计,升高业务复杂度
本文抛砖引玉,欢送大家留言交换。