日期:2014-05-16  浏览次数:20399 次

MongoDB学习笔记(十四):设计和其它补充

1.反范式设计

先看看关系数据库做个关联查询怎么做的?
比如2个表如下,一个订单有多个产品?
products:{?
'id',?
'name',?
'price',?
'desc'?
}?

orders:{?
'id',?
'user',?
'items':[product_id1,product_id2,product_id3]?
}?
这种做法关系数据库肯定没问题,一个表关联查询就行了。但mongodb则不得不查询多次,否则只能拿到产品id而已。大大降低查询性能?

那要一次的话如下设计:?
orders:{?
'id',?
'user',?
'items':[?
{ 'id':product_id1, 'name':..., 'price':..., 'desc':... },?
{ 'id':product_id2, 'name':..., 'price':..., 'desc':... },?
{ 'id':product_id3, 'name':..., 'price':..., 'desc':... }]?
}?

这样只需要一次查询便可,而且还能用elemMatch方法对items进一步过滤,就和关联查询差不多了。虽然DBRef也能做到,但DBRef不能进一步过滤。但这种方式缺点就是你在更新products时放弃了一致性。比如产品名字和价格变化,那老的数据还在order里,但这个需求是正确的,因为产品变了,但当时的订单的确不该变,不是吗。?

何时需要反范式设计:?
1.你认为引用的数据是否需要保持最新的?不是的话用反范式设计。(比如产品和订单的例子)?
2.要保持最新,那更新频率多久一次?如果极少变化,那适合用反范式设计。?
3.必须做到查询快速。那你得用反范式。?

但你可以在修改时,实时或延时同步过去,看数据量是否庞大,太庞大就算了。
?

2.不要把不断增加的数据嵌入

首先说说什么叫嵌入,数据库一对多,有2种做法,比如帖子和评论2个表,评论有个字段是帖子ID,那帖子和评论就是1对多,这个做法是引用。如果帖子有个字段叫评论(是个放ID的数组)这个就是内嵌。?

不断增加的数据,mongodb对数组追加效率是很低的。不管10个1000个10万个都不算啥,但之后要保持不变,否则会慢得你受不了。比如一个帖子的评论,那就应该使用引用做法,而不是内嵌
?
?

3.嵌入做法预留空间

mongodb如果要增加内嵌的数组,是很慢的,要分配空间。但是只是修改内容是很快的。?
所以如果你在插入数据时,明确知道总共多少条或最多多少条,可以先预留空间。放几个0或空字符串填充。
?

4.尽量避免让mongoDB做计算

由于mongodb是种无脑的大型数据库,几乎不会做任何高效的处理。虽然group,mapr