我有一个包含大约90k个文档的数据库(couchDB)。这些文档非常简单,就像这样:
{
"_id": "1894496e-1c9e-4b40-9ba6-65ffeaca2ccf",
"_rev": "1-2d978d19-3651-4af9-a8d5-b70759655e6a",
"productName": "Cola"
}
现在我希望有一天可以将这个数据库与移动设备同步。显然,90000个文档不应该一次全部放到手机上。这就是为什么我编写了过滤函数。它们应该按“产品名称”进行过滤。起初使用JavaScript编写,后来使用Erlang提高性能。这些过滤函数在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 直接编入数据库而不是作为设计文档。但我确实不知道从哪里开始,也不知道该怎么做。任何提示都有帮助。