mongoDB数据建模小案例:多列数据结构
  nQkVcpdWfLDr 2023年11月02日 46 0

1.需求

最近收到一个业务需求,需求是基于电影票售卖的不同渠道价格存储。某一个场次的电影,不同的销售渠道对应不同的价格。整理需求为:

(1).数据字段
场次信息;
播放影片信息;
渠道信息,与其对应的价格;
渠道数量最多几十个;
(2).业务查询有两种
根据电影场次,查询某一个渠道的价格;
根据渠道信息,查询对应的所有场次信息;

2.建模

(1).不好的

我们先来看其中一种典型的不好建模设计:

{
  "scheduleId": "0001",
  "movie": "你的名字",
  "price": {
    "gewala": 30,
    "maoyan": 50,
    "taopiao": 20
  }
}

数据表达上基本没有字段冗余,非常紧凑。再来看业务查询能力:

(a).根据电影场次,查询某一个渠道的价格

建立createIndex({scheduleId:1, movie:1})索引,虽然对price来说没有创建索引优化,但通过前面两个维度,已经可以定位到唯一的文档,查询效率上来说尚可;

(b).根据渠道信息,查询对应的所有场次信息

为了优化这种查询,需要对每个渠道分别建立索引,例如:

createIndex({"price.gewala":1})
createIndex({"price.maoyan":1})
createIndex({"price.taopiao":1})

但渠道会经常变化,并且为了支持此类查询,肯能需要创建几十个索引,对维护来说简直就是噩梦;

此设计行不通,否决。

(2).一般般的设计
{
  "scheduleId": "0001",
  "movie": "你的名字",
  "channel": "gewala",
  "price": 30
}

{
  "scheduleId": "0001",
  "movie": "你的名字",
  "channel": "maoyan",
  "price": 50
}

{
  "scheduleId": "0001",
  "movie": "你的名字",
  "channel": "taopiao",
  "price": 20
}

与上面的方案相比,把整个存储对象结构进行了平铺展开,变成了一种表结构,传统的关系数据库多数采用这种类型的方案。信息表达上,把一个对象按照渠道维度拆成多个,其他的字段进行了冗余存储。如果业务需求再复杂点,造成的信息冗余膨胀非常巨大。膨胀后带来的副作用会有磁盘空间占用上升,内存命中率降低等缺点。对查询的处理呢:

(a).根据电影场次,查询某一个渠道的价格

建立createIndex({scheduleId:1, movie:1, channel:1})索引

(b).根据渠道信息,查询对应的所有场次信息

建立createIndex({channel:1})索引;

更进一步的优化呢?

(3).合理的设计
{
  "scheduleId": "0001",
  "movie": "你的名字",
  "provider": [
    {
      "channel": "gewala",
      "price": 30
    },
    {
      "channel": "maoyan",
      "price": 50
    },
    {
      "channel": "taopiao",
      "price": 20
    }
  ]
}

注意看,这里使用了在MongoDB建模中非常容易忽略的结构--”数组“。查询方面的处理,是可以建立Multikey Index索引,详细信息可以参考官方文档。

(a).根据电影场次,查询某一个渠道的价格

建立createIndex({scheduleId:1, movie:1, "provider.channel":1})索引;

(b).根据渠道信息,查询对应的所有场次信息

建立createIndex({"provider.channel":1})索引;

再通过explain来验证上面两个索引是否起到作用:

db.movie.find({"scheduleId":"0001","movie":"你的名字", "provider.channel":"taopiao"}).explain()

......
  "winningPlan": {
    "stage": "FETCH",
    "inputStage": {
      "stage": "IXSCAN",
      "keyPattern": {
        "scheduleId": 1,
        "movie": 1,
        "provider.channel": 1
      },
      "indexName": "scheduleId_1_movie_1_provider.channel_1",
      "isMultiKey": true,
......
db.movie.find({"provider.channel":"taopiao"}).explain()

......
  "winningPlan": {
    "stage": "FETCH",
    "inputStage": {
      "stage": "IXSCAN",
      "keyPattern": {
        "provider.channel": 1
      },
      "indexName": "provider.channel_1",
      "isMultiKey": true,
......

3.总结

这个案例并不复杂,需求也很清晰,但确实非常典型的MongoDB建模设计,开发人员在进行建模设计时经常也会受传统数据库的思路影响,沿用之前的思维惯性,而忽略了“文档”的价值。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  sX9JkgY3DY86   2023年11月13日   45   0   0 idesedImage
  b1UHV4WKBb2S   2023年11月13日   43   0   0 ide抗锯齿
  sX9JkgY3DY86   2023年11月13日   18   0   0 分割线ideText
  b1UHV4WKBb2S   2023年11月13日   40   0   0 裁剪ideflutter
  zSWNgACtCQuP   2023年11月13日   32   0   0 ide
nQkVcpdWfLDr