Home  >  Article  >  Backend Development  >  大讨论:NOSQL中数据库的设计精髓或者设计原则是什么?

大讨论:NOSQL中数据库的设计精髓或者设计原则是什么?

WBOY
WBOYOriginal
2016-06-06 20:39:451404browse

我们先看看在mongodb下,Blog表是如何描述的:
var BlogScheme = new db.Schema({
title : String,
desc : String,
author : String,
body : String,
tags : [String],
count: { type:Number, default:0 },
hidden : { type: Boolean, default: false },
date : { type: Date, default: Date.now },
comments : [{ img: String, name: String, body: String, date: Date }],
meta : {
votes: Number,
favs: Number
}
});
  按照mongodb的设计,每篇Blog都是整篇存储的,与其它表基本没有关联,这也是NoSQL的精髓啊!但是这样子,我们该如何去统计Blog的标签tag呢?

这是我在网上摘抄的一篇文章。
其中关于NOSQL设计的一些原则。就是一篇文章就是一个表,基本上不与其他表联系,里面的评论直接放在了blog里面。我想问的是,如果这样做,怎么分页呢???
比如评论分页,,
还有就是nosql的设计原则是什么?有类似于关系型数据库的范式之说吗?

我还找到了一篇文章:
http://www.cnblogs.com/AllenDang/p/3507821.html#!comments
基本上其设计思路就是上面我提到的:将blog和评论放在一起。
这样做是减少了很多查询的。
但是出现了一个问题,如果用户的昵称变了。
那岂不是每一个这个用户评论的的blog都要去修改了????

关系型数据库,修改一下,然后join查询自然就是最新结果。
请问在mongodb里面该如何设计或者处理这种问题?

回复内容:

我们先看看在mongodb下,Blog表是如何描述的:
var BlogScheme = new db.Schema({
title : String,
desc : String,
author : String,
body : String,
tags : [String],
count: { type:Number, default:0 },
hidden : { type: Boolean, default: false },
date : { type: Date, default: Date.now },
comments : [{ img: String, name: String, body: String, date: Date }],
meta : {
votes: Number,
favs: Number
}
});
  按照mongodb的设计,每篇Blog都是整篇存储的,与其它表基本没有关联,这也是NoSQL的精髓啊!但是这样子,我们该如何去统计Blog的标签tag呢?

这是我在网上摘抄的一篇文章。
其中关于NOSQL设计的一些原则。就是一篇文章就是一个表,基本上不与其他表联系,里面的评论直接放在了blog里面。我想问的是,如果这样做,怎么分页呢???
比如评论分页,,
还有就是nosql的设计原则是什么?有类似于关系型数据库的范式之说吗?

我还找到了一篇文章:
http://www.cnblogs.com/AllenDang/p/3507821.html#!comments
基本上其设计思路就是上面我提到的:将blog和评论放在一起。
这样做是减少了很多查询的。
但是出现了一个问题,如果用户的昵称变了。
那岂不是每一个这个用户评论的的blog都要去修改了????

关系型数据库,修改一下,然后join查询自然就是最新结果。
请问在mongodb里面该如何设计或者处理这种问题?

nosql比较宽泛,不同的数据库设计原则不同。
比如mongoDB和redis都属于nosql,但是一个是文档型,一个是KV型,设计原则的区别特别大。

mongoDB的设计原则还是比较靠近关系型数据库,它的collection和table比较类似,也是insert、remove、update、find这几个基本操作,可以参考关系型数据库来设计。但是它比关系型关系灵活。
比如:一条微博可以插入9张图片,如果在MySQL中,可能这样设计:微博是一个table,图片信息是一个table,两只表做关联。或者这样设计:在微博那个table中加一个足够大的字符串类型的字段叫img_info,里面存放9张图片信息的json字符串。
而在mongoDB中,天生就是支持上述的第二种设计的。记住,是天生支持,也是就天生对img_info里面内容crud操作都异常方便。

然后回到你说的分页的问题:
分页主要就是用到2个函数:limit和skip
但是,数据量太大的时候,就不适合用skip分页了。
《MongoDB权威指南》中给出的解决方案是:获取上一页的最后一条数据,然后使用gt和limit获取下一页的数据。

关于redis的,@土豆2015 同学已经说的很详细了,就不累述了。

提醒@土豆2015 一下,mongoDB是将部分数据做内存映射,最大化利用内存,持久化还是会保存在磁盘中的。如果没有持久化,把mongoDB重启一下,数据不就都没有了啊。就算是redis这样纯内存型数据库,也是有数据持久化的。

你说的精髓的确是这样,但是只说对了一半,对于一篇博文来说评论的确可以做属性,但是评论的键你却没有选好,应该使用user_id来规避你说的昵称改变带来的问题。(你没有办法把所有东西全部塞到一个document里面对吧,你总有user_info集对吧)
所以mongodb的设计精髓并不是一味提倡你反范式,而是要懂得取舍。
再说说你问的统计tag的问题。
单看你的blog实体的tag设计成了list结构
就像是

<code>tags = {
    "blog_id_111_tag": ["NBA", "姚明", "季后赛"],
}
</code>

要统计的办法其实很多,你应该是想统计topic_1下的博文有多少,topic_2下的博文又有多少对吧。其实也很好统计,在python中你可以使用字典推导式把这个tag反转。如下:

<code>tag_mapper = {v:k for k in tags for v in tags[k]}
#这样你就得到了
{
    "NBA": "blog_id_111_tag",
    "姚明": "blog_id_111_tag",
    "季后赛": "blog_id_111_tag"
}
</code>

每篇博文都采取这样的方式统计,就能够统计出每个tag下面有哪些同类的博文了。

1.非关系型数据库产品的实质是关系型数据库产品的功能阉割版。通过阉割【关系】等功能,来获取更高的性能,以及更方便的使用性。

2.从上述实质出发,非关系型数据库产品适合用来做数据仓库。因为数据仓库中的数据的特点是量大、关系松散。

3.但是,非关系型数据库由于性能高,因此不少的人开始打它的主意,想把关系型数据也丢进来。这样做肯定有问题,因为你站在代码层上,试图自己在没有关系功能的非关系型数据库引擎上,自己来维护关系功能,肯定会付出昂贵的代价。这个代价可能是:
----1.非常低的效率。比如试图把一个分布在关系型数据库中多个属性表中的对象,组合回一个大对象放在非关系型数据库里,导致每次查询一个属性时,引擎不得不把整个大对象提取出来。
----2.非常脏的数据。由于大部分非关系型数据库产品无多表、库事务,因此有人通过创建单独的关系库,来维系两个不同对象的库的关系。但由于无事务,导致几个操作无法保证事务原子,因此经常产生冲突,导致数据“变脏”。

4.综上,当你满脑子都是如何处理强关系时,请不要坚持用非关系型数据库,不然你肯定会被坑。

对于关系型数据库来说,ACID是强一致性的四个要求(ACID:atomicity, consistency, isolation, durability;)

而BASE是NoSQL数据库通常对可用性及一致性的弱要求原则,BASE:Basically Available, Soft-state, Eventually Consistent。

nosql是不管关系结构的,但是我们可以利用已有的数据库结构来构造关系!

mongodb我没用过,我nosql用的redis.处理分页如下:

先有一个全量的blog list,只存blog.id。比如名字叫list:blog.
再有一个hash对应blog数据结构.命名可以这样blog:。
新建一个blog的时候,结合redis的transaction>>start
redis:rpush('list:blog', );//先往list存id
redis:hmset('blog:'+, 'title', ..., 'content', ....)//再存hash
transaction


分页的时候结合sort limit命令操作list和hash
sort list:blog limit 0 10 get # get blog:->title get blog:->content
当然还可以根据blog的某些属性进行sort
sort list:blog by blog:->createtime desc limit 0 10 get # get blog:->title get blog:*->content

至于评论的分页做法类似。

从你的问题上看出来,你的数据完全依赖mongodb,完全是依赖内存的,你的数据持久化是在哪里呢?

我来发表一下自己的见解吧:
讲要更新的数据放在一个集合,而不是将要显示的数据放在一个集合。那么将评论放在blog表就是错误的了。
因为无法解决这样的问题:
用户的昵称更新了怎么办。
因此,设计原则就是将要更新的放在一起。

去范式,分布式

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn