[英]How to improve Update query in arangodb
我的收藏馆藏有超过1500万份文档。 在这1500万份文档中,我每小时更新2万条记录。 但是更新查询需要很长时间才能完成(大约30分钟)。
文献:
{“ inst”:“ instance1”,“ dt”:“ 2015-12-12T00:00:000Z”,“ count”:10}
我有一个包含20k实例要更新的数组。
我的查询如下所示:
For h in hourly filter h.dt == DATE_ISO8601(14501160000000)
For i in instArr
filter i.inst == h.inst
update h with {"inst":i.inst, "dt":i.dt, "count":i.count} in hourly
有没有优化的方法来做到这一点。 我在inst上有哈希索引,在dt上有skiplist索引。
更新资料
我无法在查询中手动使用20k inst,因此以下是仅2 inst的执行计划:
FOR r in hourly FILTER r.dt == DATE_ISO8601(1450116000000) FOR i IN [{"inst":"0e649fa22bcc5200d7c40f3505da153b", "dt":"2015-12-14T18:00:00.000Z"}, {}] FILTER i.inst == r.inst UPDATE r with {"inst":i.inst, "dt": i.dt, "max":i.max, "min":i.min, "sum":i.sum, "avg":i.avg, "samples":i.samples} in hourly OPTIONS { ignoreErrors: true } RETURN NEW.inst Execution plan: Id NodeType Est. Comment 1 SingletonNode 1 * ROOT 5 CalculationNode 1 - LET #6 = [ { "inst" : "0e649fa22bcc5200d7c40f3505da153b", "dt" : "2015-12-14T18:00:00.000Z" }, { } ] /* json expression */ /* const assignment */ 13 IndexRangeNode 103067 - FOR r IN hourly /* skiplist index scan */ 6 EnumerateListNode 206134 - FOR i IN #6 /* list iteration */ 7 CalculationNode 206134 - LET #8 = i.`inst` == r.`inst` /* simple expression */ /* collections used: r : hourly */ 8 FilterNode 206134 - FILTER #8 9 CalculationNode 206134 - LET #10 = { "inst" : i.`inst`, "dt" : i.`dt`, "max" : i.`max`, "min" : i.`min`, "sum" : i.`sum`, "avg" : i.`avg`, "samples" : i.`samples` } /* simple expression */ 10 UpdateNode 206134 - UPDATE r WITH #10 IN hourly 11 CalculationNode 206134 - LET #12 = $NEW.`inst` /* attribute expression */ 12 ReturnNode 206134 - RETURN #12 Indexes used: Id Type Collection Unique Sparse Selectivity Est. Fields Ranges 13 skiplist hourly false false n/a `dt` [ `dt` == "2015-12-14T18:00:00.000Z" ] Optimization rules applied: Id RuleName 1 move-calculations-up 2 move-filters-up 3 move-calculations-up-2 4 move-filters-up-2 5 remove-data-modification-out-variables 6 use-index-range 7 remove-filter-covered-by-index Write query options: Option Value ignoreErrors true waitForSync false nullMeansRemove false mergeObjects true ignoreDocumentNotFound false readCompleteInput true
我假设选择部分(而不是更新部分)将成为此查询的瓶颈。
该查询似乎有问题,因为对于每个与第一个过滤器匹配的文档( h.dt == DATE_ISO8601(...)
),将在instArr
数组中的20,000个值上进行迭代。 如果instArr
值是唯一的,则将仅匹配其中的一个值。 另外,没有索引将用于内部循环,因为索引选择已在外部循环中发生。
与其遍历instArr
所有值, instArr
将附带的==
比较变成IN
比较。 如果instArr
是实例名称的数组,这已经可以工作,但是它似乎是实例对象的数组(至少由inst
和count
属性组成)。 为了在IN
比较中使用实例名称,最好有一个专用的实例名称数组,以及一个用于count
和dt
值的转换表。
以下是使用JavaScript生成这些代码的示例:
var instArr = [ ], trans = { };
for (i = 0; i < 20000; ++i) {
var instance = "instance" + i;
var count = Math.floor(Math.random() * 10);
var dt = (new Date(Date.now() - Math.floor(Math.random() * 10000))).toISOString();
instArr.push(instance);
trans[instance] = [ count, dt ];
}
instArr
将如下所示:
[ "instance0", "instance1", "instance2", ... ]
和trans
:
{
"instance0" : [ 4, "2015-12-16T21:24:45.106Z" ],
"instance1" : [ 0, "2015-12-16T21:24:39.881Z" ],
"instance2" : [ 2, "2015-12-16T21:25:47.915Z" ],
...
}
然后可以使用绑定变量(如上面的变量那样命名)将这些数据注入查询中:
FOR h IN hourly
FILTER h.dt == DATE_ISO8601(1450116000000)
FILTER h.inst IN @instArr
RETURN @trans[h.inst]
请注意,ArangoDB 2.5尚不支持@trans[h.inst]
语法。 在该版本中,您将需要编写:
LET trans = @trans
FOR h IN hourly
FILTER h.dt == DATE_ISO8601(1450116000000)
FILTER h.inst IN @instArr
RETURN trans[h.inst]
另外,2.5的IN
列表较长。 IN列表的性能随IN
列表的长度呈二次方下降。 因此,在此版本中,将instArr
为最多2,000个值是instArr
。 这可能需要发出多个具有较小IN
列表的查询,而不是仅发出具有大IN
列表的查询。
更好的选择是使用ArangoDB 2.6、2.7或2.8,它们没有此问题,因此不需要解决方法。 除此之外,您还可以在较新的ArangoDB版本中使用稍短的查询版本。
还要注意,在以上所有示例中,我都使用RETURN ...
而不是原始查询中的UPDATE
语句。 这是因为我所有的测试都表明查询的选择部分是主要问题,至少与我生成的数据有关。 关于UPDATE
原始版本的最后说明:用i.inst
更新每个文档的inst
值似乎是i.inst == h.inst
,因为i.inst == h.inst
使得该值不会更改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.