如何改进arangodb中的更新查询

时间:2015-12-15 21:05:06

标签: arangodb

我有一个收藏超过1500万份文件的藏品。在这1500万份文件中,我每小时更新20k条记录。但更新查询需要很长时间才能完成(周围30分钟)。

文件:

{“inst”:“instance1”,“dt”:“2015-12-12T00:00:000Z”,“count”:10}

我有一个数组,可以容纳20k个实例进行更新。

我的查询如下所示:

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

是否有任何优化的方法。我对inst上的哈希索引和dt上的skiplist索引。

  

更新

我无法手动在查询中使用20k inst,因此以下是2 inst的执行计划:

{{1}}

1 个答案:

答案 0 :(得分:4)

我认为选择部分(不是更新部分)将成为此查询的瓶颈。

查询似乎有问题,因为对于匹配第一个过滤器(h.dt == DATE_ISO8601(...))的每个文档,将在instArr数组中的20,000个值上进行迭代。如果instArr值是唯一的,则只有一个值匹配。此外,内部循环不会使用任何索引,因为索引选择已经在外部循环中发生。

不是循环instArr中的所有值,而是将随附的==比较转换为IN比较。如果instArr是一个实例名称数组,那么它就已经有效了,但它似乎是一个实例对象数组(至少包含属性instcount)。为了在IN比较中使用实例名称,最好有一个专用的实例名称数组,以及countdt值的转换表。

以下是使用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列表的长度呈二次方式降低。因此,在此版本中,将instArr的长度限制为最多2,000个值是有意义的。这可能需要使用较小的IN列表发出多个查询,而不是仅使用大IN列表的查询。

更好的选择是使用ArangoDB 2.6,2.7或2.8,它们没有这个问题,因此不需要解决方法。除此之外,您可以在较新的ArangoDB版本中使用稍短版本的查询。

另请注意,在上述所有示例中,我使用了RETURN ...而不是原始查询中的UPDATE语句。这是因为我的所有测试都显示查询的选择部分是主要问题,至少是我生成的数据。 关于UPDATE原始版本的最终说明:使用inst更新每个文档的i.inst值似乎是减少的,因为i.inst == h.inst所以价值赢了&#39}。改变。