MongoDB Schema Design 数据库设计
介绍使用MongoDB设计数据库,就不要按照关系型数据库的思维来做,如范式化数据。因为MongoDB不支持服务端的join查询。一般来说,在对于顶端的对象都要用单独的collection进行存储。 当然不需要望每个对象都要创建一个collection。可替代的策略是使用嵌入对象(embed object)。 例子,在下面的图,有两个collection。 分别是student和courses。 student document嵌入了address对象并和score document。并且有个引用到courses。
相比较关系模型,一般会把score单独存储到一张表中并且有个外键关联到student。 Embed vs. Reference(内嵌VS引用)MongoDB模型设计关键问题在于是单独创建collection,还是作为内嵌对象? 在关系型数据库中,每个子元素都要单独创建一张表。 在MongoDB中,这并不推荐。 内嵌对象性能要更为高效。 数据分配在了硬盘上; 客户端和服务器通信的消耗基本不存在。 因此 "为什么我不需要内嵌对象?" 为什么引用非常慢?让我们考虑这个student的例子。如果我们有个student对象并执行 print( student.address.city ); 这个操作用内嵌对象的话会非常快速并且如果student在RAM中,这个内嵌对象同样也在RAM中。 print( student.scores[0].for_course.name ); 如果是第一次访问course。shell或者驱动必须执行下列查询。 // 伪代码!
student.scores[0].for_course = db.courses.findOne({_id:_course_id_to_find_}); 每个引用遍历都对于数据库是一个查询。 这个collection在_id上有个索引。 这个查询还是非常快的。然而, 即使所有的数据在RAM中,从应用服务器到数据库之间的通信也会有延迟。 一般来说,期望在RAM中1ms命中缓存。如果我们循环1000个student,查询每个student应用就会很慢了。 超过1分钟。 然而, 如果我们紧紧需要查询一个单独的元素,时间就是1ms 并且页面读取是完全可以接受的。 (注意如果在db缓存中, 返回1000student实际时间要小于1分钟) 下面是一些使用内嵌对象和引用的规则:
示例让我们看看一些示例
索引的选择第二个比较重要的是索引的选择. 作为通用规则,如果在关系型数据库需要添加索引,那么MongoDB也一样。
MongoDB profiling facility 提供了你应该添加索引的信息。 注意的是,添加索引会降低写入速度,对于读取频率高的collection可以创建多点的索引。 写频率较高的话,索引开销就很昂贵。 |