使用基于文档的nosql(mongodb、couchdb和riak等)查询关系数据的性能
为了跟进我的问题,我读了几篇关于这个主题的文章: 他们似乎认为nosql可以处理规范化的关系数据 让我们继续我之前的例子,一个CMS系统,它有两种类型的数据:article和authors,其中article有一个对author的引用(通过ID) 以下是系统需要支持的操作:使用基于文档的nosql(mongodb、couchdb和riak等)查询关系数据的性能,mongodb,couchdb,rdbms,riak,nosql,Mongodb,Couchdb,Rdbms,Riak,Nosql,为了跟进我的问题,我读了几篇关于这个主题的文章: 他们似乎认为nosql可以处理规范化的关系数据 让我们继续我之前的例子,一个CMS系统,它有两种类型的数据:article和authors,其中article有一个对author的引用(通过ID) 以下是系统需要支持的操作: 按id和作者一起获取文章 按特定作者获取所有文章 查找前10篇文章,作者按创作日期排序 如果相同的数据存储在RDBMS上,与相同的操作相比,我想了解这些操作的性能特别是,请指定操作是否使用MapReduce,是否需要多次
在Riak和Mongodb上可用。对于Mongodb,您不会将嵌入文档用于作者记录。因此,预连接已退出,它是到数据库的多次访问。但是,您可以缓存作者,并且只需要对每条记录进行第二次访问。您指出的查询在MongoDB中非常简单
var article = db.articles.find({id: article_id}).limit(1);
var author = db.authors.find({id: article.author_id});
如果您使用ORM/ODM来管理应用程序中的实体,这将是透明的。不过去db要两次。他们的反应应该很快,但两个点击根本不应该被注意到
查找给定作者的文章正好相反
var author = db.authors.find({id: author_name}).limit(1);
var articles = db.articles.find({author_id: author.id});
同样,两个查询(但单个作者获取)应该很快,并且可以很容易地缓存
var articles = db.articles.find({}).sort({created_at: 1}).limit(10);
var author_ids = articles.map(function(a) { return a.author_id });
var authors = db.authors.find({id: { '$in': authors_ids }});
最后,还是两个查询,只是稍微复杂一点。您可以在mongo shell中运行这些命令,以查看结果
我不确定这是否值得写一个地图来完成。几次快速往返可能会有更多的延迟,但mongo协议相当快。我不会过分担心的
最后,这样做的实际性能影响。。。因为理想情况下,您只需要查询文档中的索引字段,所以应该非常快。唯一的额外步骤是第二次往返以获取其他文档,这取决于应用程序和数据库的结构,这可能根本不是什么大问题。您可以告诉mongo只评测超过给定阈值的查询(打开时默认为100或200毫秒),这样您就可以关注随着数据的增长程序所花费的时间
RDMS不提供的一种适合您的方法是更容易地分解数据。当您将应用程序扩展到CMS之外以支持其他内容,但使用相同的身份验证存储时,会发生什么情况?它现在正好是一个完全独立的数据库,在许多应用程序中共享。跨dbs执行这些查询要简单得多——使用RDMS存储,这是一个复杂的过程
我希望这对您的NoSQL发现有所帮助
按id和作者一起获取文章
SQL:
- 1查询
- 2索引查找
- 2数据查找
- 返回的数据=文章+作者
- 2查询
- 2索引查找
- 2数据查找
- 返回的数据=文章+作者
- 1查询
- 1索引查找
- N数据查找
- 返回的数据=N个项目
- 1查询
- 1索引查找
- N数据查找
- 返回的数据=N个项目
- 1查询
- 2索引查找
- 11到20个数据查找(文章然后是唯一作者)
- 返回的数据=10篇文章+10位作者
- 2个查询(
,articles.find().sort().limit(10)
authors.find({$in:[article\u authors]})
- 2索引查找
- 11到20个数据查找(文章然后是唯一作者)
- 返回的数据=10篇文章+1到10位作者
摘要 在两种情况下,MongoDB需要一个额外的查询,但在下面执行大部分相同的工作。在某些情况下,MongoDB通过网络返回的数据较少(没有重复条目)。联接查询往往受到以下要求的限制:所有要联接的数据都位于同一个框中。如果作者和文章位于不同的位置,则您最终会执行两个查询 MongoDB倾向于获得更好的“原始”性能,因为它不会在每次写入时刷新到磁盘(因此它实际上是一种“持久性”权衡)。它还有一个更小的查询解析器,因此每个查询的活动更少
从基本性能的角度来看,这些东西非常相似。它们只是对您的数据和您想要进行的权衡做出了不同的假设。只是想为任何可能好奇的人提供一个CouchDB答案。:) 正如上面第一个答案中提到的,将author文档嵌入到article文档中是不明智的,因此下面的示例假设两种文档类型:articles和authors CouchDB使用通常用JavaScript编写的MapReduce查询(但Python、Ruby、Erlang和其他可用)。MapReduce查询的结果在第一次请求时存储在一个索引中,该存储的索引用于将来的所有查找。对数据库的更改将在进一步请求时添加到索引中 CouchDB的API完全基于HTTP,因此对数据库的所有请求都是各种URL上的HTTP动词(GET、POST、PUT、DELETE)。我会的 GET /db/{article_id} GET /db/{author_id}
function (doc) {
if (doc.type === 'article') {
emit(doc.author_id, doc);
}
}
GET /db/_design/cms/_view/articles_by_author?key="{author_id}"
function (doc) {
function arrayDateFromTimeStamp(ts) {
var d = new Date(ts);
return [d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()];
}
var newdoc = doc;
newdoc._id = doc.author_id;
newdoc.created_at = arrayDateFromTimeStamp(doc.created_at);
if (doc.type === 'article') {
emit(newdoc.created_at, newdoc);
}
}
GET /db/_design/cms/_view/articles_by_date?descending=true&limit=10&include_docs=true
{"rows":[
{ "id":"article_id",
"key":[2011, 9, 3, 12, 5, 41],
"value":{"_id":"author_id", "title":"..."},
"doc":{"_id":"author_id", "name":"Author Name"}
}
]}