couchDB的过滤速度非常慢,即使使用erlang也是如此
very slow filters with couchDB even with erlang
我有一个数据库(couchDB),其中包含大约90k个文档。文档非常简单,像这样:
{
"_id": "1894496e-1c9e-4b40-9ba6-65ffeaca2ccf",
"_rev": "1-2d978d19-3651-4af9-a8d5-b70759655e6a",
"productName": "Cola"
}
现在我希望有一天将这个数据库与移动设备同步。显然,9万名医生不应该同时打电话。这就是我写过滤函数的原因。这些应该通过"productName"进行过滤。首先在Javascript中,然后在Erlang中获得性能。这些Filter函数在JavaScript中是这样的:
{
"_id": "_design/local_filters",
"_rev": "11-57abe842a82c9835d63597be2b05117d",
"filters": {
"by_fanta": "function(doc, req){ if(doc.productName == 'Fanta'){ return doc;}}",
"by_wasser": "function(doc, req){if(doc.productName == 'Wasser'){ return doc;}}",
"by_sprite": "function(doc, req){if(doc.productName == 'Sprite'){ return doc;}}"
}
}
,像这样在Erlang中:
{
"_id": "_design/erlang_filter",
"_rev": "74-f537ec4b6508cee1995baacfddffa6d4",
"language": "erlang",
"filters": {
"by_fanta": "fun({Doc}, {Req}) -> case proplists:get_value(<<'"productName'">>, Doc) of <<'"Fanta'">> -> true; _ -> false end end.",
"by_wasser": "fun({Doc}, {Req}) -> case proplists:get_value(<<'"productName'">>, Doc) of <<'"Wasser'">> -> true; _ -> false end end.",
"by_sprite": "fun({Doc}, {Req}) -> case proplists:get_value(<<'"productName'">>, Doc) of <<'"Sprite'">> -> true; _ -> false end end."
}
}
为了保持简单,这里没有查询,只有一个"硬编码"字符串。过滤器都工作了。问题是它们太慢了。我先用Java编写了一个测试程序,然后用Perl测试过滤文档所需的时间。下面是我的一个Perl脚本:
$dt = DBIx::Class::TimeStamp->get_timestamp();
$content = get("http://127.0.0.1:5984/mobile_product_test/_changes?filter=local_filters/by_sprite");
$dy = DBIx::Class::TimeStamp->get_timestamp() - $dt;
$dm = $dy->minutes();
$dz = $dy->seconds();
@contArr = split("'n", $content);
$arraysz = @contArr;
$arraysz = $arraysz - 3;
$'="'n";
print($dm.':'.$dz.' with '.$arraysz.' Elements (JavaScript)');
现在是悲伤的部分。这些是我得到的次数:
2:35 with 2 Elements (Erlang)
2:40 with 10000 Elements (Erlang)
2:38 with 30000 Elements (Erlang)
2:31 with 2 Elements (JavaScript)
2:40 with 10000 Elements (JavaScript)
2:51 with 30000 Elements (JavaScript)
顺便说一下,这些是分和秒。这个数字是过滤器返回的元素数量,数据库中有90k个元素。最令人惊讶的是,Erlang过滤器一点也不快。
请求所有元素只需要9秒。创建了大约15个视图。但我不可能在手机上传输所有文件(音量和安全原因)。
是否有一种方法可以在视图上过滤以获得性能提高?或者是我的erlang过滤器函数出了问题(我对JavaScript过滤器的时间并不感到惊讶)。
编辑:正如pgras指出的,为什么这是缓慢的原因是张贴在这个问题的答案。为了让erlang过滤器运行得更快,我需要进入下面的"层",并将erlang直接编程到数据库中,而不是作为_design文档。但我真的不知道从哪里开始,怎么做。
我问这个问题已经有一段时间了。但我想我应该回来分享我们最终解决这个问题的方法。
所以简短的答案是过滤器的速度不能真正提高。
原因在于过滤器的工作方式。如果您检查数据库更改。他们在这里:
http://<ip>:<port>/<databaseName>/_changes
此文档包含属于您的数据库的所有更改。如果您在数据库中执行任何操作,则会添加新的行。当现在想要使用过滤器时,过滤器将从json解析为指定的语言,并用于该文件中的每一行。要清楚的是,据我所知,解析也为每行完成。这不是很有效,不能改变。
所以我个人认为对于大多数用例过滤器是缓慢的,不能使用。这意味着我们必须找到一个解决办法。我并不是说我有一个通解。我只能说在这里我们可以使用视图而不是过滤器。视图在内部生成树,与过滤器相比,它和光一样快。一个简单的过滤器也存储在设计文档中,看起来像这样:
{
"_id": "_design/all",
"language": "javascript",
"views": {
"fantaView": {
"map": "function(doc) { 'n if (doc.productName == 'Fanta') 'n emit(doc.locale, doc)'n} "
}
}
}
其中fantaView是视图的名称。我想这个函数是不言自明的。所以这就是我们所做的,我希望它能帮助别人,如果他遇到类似的问题。
我可能是错的,但过滤器函数应该返回布尔值,所以尝试改变一个:
function(doc, req){ return doc.productName === 'Fanta';}
编辑:这是一个解释为什么它是缓慢的(至少与JavaScript)…
一种解决方案是使用视图选择要同步的文档的id,然后通过指定要同步的doc_ids开始同步。
例如:
function(doc){
emit(doc.productName, doc._id)
}
你可以用_design/docs/_view/by_producName?关键="芬达"
然后用找到的doc id开始复制…
一般来说,couchDB过滤器很慢。其他人已经解释了为什么他们行动缓慢。我发现使用过滤器的唯一合理方法是使用"since"。否则,在一个相当大的数据库中(我的数据库有47k个文档,它们是复杂的文档),过滤器不起作用。我们从开发部门迁移到生产部门(几百个文档到47k个文档)的过程中吸取了教训。我们还将设计更改为查询视图,因为我们需要一个类似连续提要的行为,我们使用了Spring的@Scheduled
- 有可能过滤来自嵌入式YouTube的声音吗
- 为什么我的d3.jsselectAll+过滤器没有过滤
- ui网格日期单元格过滤器,过滤日期格式导致显示错误的日期
- Angular:使用选择列表选择过滤代码中的对象
- 在单击时过滤 JSON
- 如何在BookshelfJS中通过加入来过滤结果
- 如何使用javascript过滤复杂的json对象
- 如何应用带过滤器的ng if来过滤记录,并在同一页面中显示两个不同的视图
- 过滤AngularJs中的数据
- 通过API调用过滤数据
- 使用angularjs内置过滤器过滤代码中的特定属性
- 如何在重建URL后从URL中传递过滤值,目的是使用Angular2和Typescript实现无限滚动
- 相对于角度控制器中的另一个阵列过滤阵列项目
- 如何在D3.js中绘制地图投影上的点,并使用范围滑块过滤数据
- 使用PHP通过HTML表单选项选择器过滤MYSQL结果
- 尝试过滤“;引号"基于'"类别“;使用流星&mongo
- Angular中的过滤和$http承诺
- 使用jquery grep过滤具有值数组的json对象
- 过滤后如何将一行推送到表中
- couchDB的过滤速度非常慢,即使使用erlang也是如此