MongoDB 字段应该扁平还是结构化?

2013-10-18 09:44:07 +08:00
 qiayue
搜索了一下,好像没找到多少相关资料。
在谷歌 JSON 风格指南 https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md 中说:
JSON中的数据元素应以扁平化方式呈现。不能为了方便而将数据任意分组。

考虑到 MongoDB 也是以类 JSON 格式存储数据,那么,在 MongoDB 中的字段是否也应该是扁平化的呢?
5858 次点击
所在节点    MongoDB
13 条回复
breeswish
2013-10-18 09:53:18 +08:00
每个小颗粒单位尽量扁平化,如果有整体小数据则可以在这里结构化。(因为MongoDB的查询和处理语言对于扁平化很方便,对于结构化的数据不方便)
Ricepig
2013-10-18 11:21:01 +08:00
结构化和分组的目的只有一个,那就是可读性吧
shiny
2013-10-18 11:23:36 +08:00
这个命题比一般人想象的更复杂,这个不应该参照普通 JSON 数据来。
应该搜索 「MongoDB 范式化 反范式化」。
举个我的血泪栗子:内嵌的 JSON 如果频繁更新,它就不应该是内嵌的,否则会有性能问题。
hepochen
2013-10-18 11:48:11 +08:00
JSON是JSON, MongoDB是MongoDB。

不论是扁平还是多层内嵌,是个人的选择问题;但只有一个前提,就是不能影响数据库的性能。

扁平相对而言是会简单一些,内嵌的,具体场景中,性能反倒会更高。

因为在MongoDB的底层存储中,对内嵌文档的处理并非是大家想象中的那般结构化,但比如要更新`collection.field1.field2.field3.field5`这到底更新了哪段信息?如果我有个字段名就是`field1.field2`的联合呢?

@shiny 内嵌文档的大小也在频繁变化么?
turing
2013-10-18 11:52:03 +08:00
我觉得嵌入文档还是分表存取决于数据库是主要是用来读还是写的

如果仅是展示用,比如从其他地方获取结构化的数据,保存在单一集合里,不用修改的方式,内嵌文档很好用,也很方便,如果频繁操作修改内嵌文档,就不太方便了。
shiny
2013-10-18 11:55:44 +08:00
除了性能,还要考虑需求实现是否方便。比如涉及日期范围的,用内嵌将会很痛苦(比如很多人把日期当做键而不是一个值……),操作内嵌文档,大多数命令也和范式化的不同。尤其是为了简洁,没什么多余字段的内嵌文档。
其次是大尺寸内嵌文档更难控制需要的字段,以前线上发现 tornado 内存不断增长却找不到原因,最后谨慎选择了下字段排除了不需要的、数据量大的字段就好了。

@hepochen 我的情况是不断 insert 的数据,卡得掉眼泪。
qiayue
2013-10-18 12:49:40 +08:00
@breeswish @Ricepig @shiny @hepochen @turing @shiny 多谢!
所以还是要看具体的业务场景,并且扁平化一些,性能好些
hepochen
2013-10-18 12:56:22 +08:00
呃,@shiny 同学,你可以考虑请我吃饭了。

用日期作为key,也未必是坏事。比如用作统计的,而且年/月/日这些固定的(非range性质)的,可以用正则的前向匹配,同时,也是可以使用索引的。所以,这反而是一个高效的处理办法。

但有一个问题,比如`2012-09`这样的key来存储一个月的数据(按天),那么,(有人)推荐的做法,是创建这个document的时候,就填充好31天的空数据。

呃,为什么是`2012-09`而不是`2012-9`呢? 这跟`2012-10`对比,会产生大小的问题,也可以很漂亮地解决时间被str化后的排序问题。

- - - - -

所有的字段如何控制,都是个人的一种选择。但是内嵌字段中出现一些特殊值,比如`$`开头的, 带`.`的,则要对MongoDB要更了解一些,不然很容易入坑。

- - - -

用内嵌文档,不会产生性能的问题。

用内嵌文档,并且不断insert,这会是性能问题产生的原因。

MongoDB是文档型的数据库,一个文档被创建的时候,默认会有保留多一点的空区域(这种机制,也会MongoDB等NoSQL数据库比较占磁盘空间的原因),可以方便以后的更新操作。但是,这个区域占满之后,磁盘空间就需要重新分派(这是极低效的)。

如果这是过程中,有多一点量的写操作涌进来,呃,肯定会“卡得掉眼泪”了。
zack
2013-10-18 13:05:08 +08:00
从存储空间的占用角度来看,尽量优先使用扁平化
shiny
2013-10-18 13:05:19 +08:00
@hepochen 谢谢
1、年月日我们是涉及一定范围内的统计的,更别说什么排序之类的,除非把数据全部取出来自己排。而如果是范式化的,就有现成的——当然数据处理不应该交给 MongoDB,这个时候才念起 SQL 的好来。
而且时间久了有可能出现巨大的内嵌文档(当然这个是设计错误,但是处理起来范式化的设计更容易处理点)。

2、字段是指有的字段包含大量数据,而不是说特殊字符。包含大量数据的字段,而且不是 PHP 这类用完就销毁的语言很可能内存爆满。范式化也有个好处是精准控制需要的数据。

3、我是在翻书后才知道,原话是「不断增长的内嵌文档将导致 IO 瓶颈」。如果 update 数据增长,也会是有问题的。当时我就一个进程后台默默写 MongoDB,也差不多写到了 IO 瓶颈——当然,数据量越大卡得越明显,刚设计完的时候还没发现。
shiny
2013-10-18 13:18:36 +08:00
@hepochen 有时需求很难实现,我会借助 map reduce,好像内嵌文档的 map reduce 比范式化的不易?

因为就一个人搞技术,情况复杂时有问题也没人讨论。

反正经历过这么一次后,把数据放 MongoDB 是谨慎又谨慎了。
breeswish
2013-10-18 17:25:16 +08:00
@shiny 很多东西要试了才知道
goofansu
2013-10-19 01:10:11 +08:00
有本书叫mongodb design pattern,觉得还不错

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/85963

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX