大项目 - 数据库表单设计和优化想法 | 青训营

76 阅读3分钟

在我们项目的开发初期,大家有在讨论主数据库的选型,比较多的两个声音是MongoDB和MySQL,分别代表了文档型数据库和关系型数据库的典型。因为大家经验都不算丰富,没办法直观的比较出两者哪个更适合我们的项目。就提出我们双管齐下,针对两种数据库都设计一下表单以及对应的优化思路,来个横向对比。

这篇笔记主要会总结一下MongoDB的设计和优化想法。

表单设计

用户相关

users

名称类型属性说明
user_idObjectId主键,用于唯一标识用户。
usernameString用户名。
passwordString密码(工程上应该使用哈希后的密码而不是明文)。
profileDoc嵌套文档,用于存储用户相关的一些其它元数据。

profile

名称类型属性说明
follow_countInteger用户关注的人数。
follower_countInteger用户的粉丝数量。
work_countInteger用户发布的视频数量。
total_favoritedInteger用户喜欢的视频数量。
favorite_countInteger用户获赞数量。
avatarString用户头像的URL。
background_imageString用户背景图片的URL。

视频流

videos

名称类型属性说明
video_idObjectId主键,用于唯一标识视频。
author_idObjectId视频作者的用户ID。
titleString视频标题。
play_urlString视频播放URL。
cover_urlString视频封面图片URL。
favorite_countInteger视频的点赞数。
comment_countInteger视频的评论数。
publish_timeDate视频的发布时间。

互动相关

favorites

名称类型属性说明
user_idObjectId喜欢视频的用户ID。
video_idObjectId被喜欢的视频ID。
timestampDate点赞的时间。

comments

名称类型属性说明
comment_idObjectId主键,用于唯一标识评论。
user_idObjectId发表评论的用户ID。
video_idObjectId被评论的视频ID。
contentString评论的内容。
timestampDate评论的创建时间。

关注关系

relations

名称类型属性说明
from_user_idObjectId发起关注操作的用户ID。
to_user_idObjectId被关注的用户ID。
timestampDate关注操作的时间。

消息

名称类型属性说明
from_user_idObjectId发送消息的用户ID。
to_user_idObjectId接收消息的用户ID。
contentString消息的内容。
timestampDate消息发送的时间。

用数据库ERM图表示为:

image.png

优化想法

这里列举了一些优化的思路,可能有考虑不周全甚至有误,欢迎讨论和指正。

  1. 索引的优化:

    1. 针对发布列表API,因为要真是一个用户发布的所有视频,并且按照时间倒序排列,因此可以对 videos 建立一个联合索引 (author_id, -publish_time) ,这里 -publish_time 前面的减号代表倒序。
    2. 类似的,针对喜欢列表和评论列表API,我们可以在 favorites 表和 comments 表中对 user_id 字段建立索引。另外,虽然API文档里面没有特别说明,但是我们可以想到不管是点赞列表还是评论列表,我们都希望是以时间倒序排列(也就是最近的在前面),那么最好是建立一个联合索引(user_id, -timestamp)
    3. 对于关注列表和粉丝列表API,我们可以在 relationships 表中对 from_user_idto_user_id 建立索引,以便快速的找到某个用户的粉丝列表和关注对象列表。同理,按时间倒序排列,也就是应该更进一步设计成 (from_user_id, -timestamp)(to_user_id, -timestamp) 这样的联合索引。
    4. 同样的,在messages 表中,也可以建立 (from_user_id, -timestamp)(to_user_id, -timestamp) 这样的联合索引。
  2. 表的优化:

    对于表的存储,考虑到超大数据量的场景,我们需要对表进行水平分割/切片(honrizontal sharding)

  3. 缓存的优化:

    a. 对于高频查询的字段,可以使用 Redis 来对近期新建的数据和近期被访问的数据进行缓存,因为这些数据在短时间内被再次访问的几率和频率都很大,将它们进行缓存可以有效地减少直接对数据库的请求,降低数据库的压力。而且因为缓存使用的是内存存储,速度远高于数据库(硬盘存储),大大提高了查询效率。