【问题标题】:Strange behaviour with vertex centric indexes以顶点为中心的索引的奇怪行为
【发布时间】:2021-03-22 14:43:00
【问题描述】:

我无法理解如何在 ArangoDB 中正确使用以顶点为中心的索引。

在我的烹饪应用程序中,我有以下图表架构:(recipe)-[hasConstituent]->(ingredient)

假设我想要所有需要少于 0 克胡萝卜的食谱。结果当然是空的。

FOR recipe, constituent, p IN INBOUND 'ingredients/carrot' hasConstituent
    FILTER constituent.quantity.value < 0
    RETURN recipe._key

胡萝卜关联了 400.000 个食谱,这个查询需要大约 3.9 秒。很好。

现在我在_to,quantity.value 属性的hasConstituent 集合中创建一个以顶点为中心的索引,估计选择性为100%。

我希望它按数字顺序对索引进行排序,然后显着提高 FILTER 或 SORT/LIMIT 请求的速度,但现在之前的请求需要大约 7.9 秒...如果我使索引“稀疏”,它需要与没有索引相同的时间(~3.9s)

我在这里错过了什么?

最难理解的是解释结果给出的执行计划与profile结果不同。这是解释,一切都很好,应该立即获取结果:

Execution plan:
 Id   NodeType          Est.   Comment
  1   SingletonNode        1   * ROOT
  5   TraversalNode        1     - FOR recipe  /* vertex */, constituent  /* edge */ IN 1..1  /* min..maxPathDepth */ INBOUND 'ingredients/carrot' /* startnode */  hasConstituent
  6   CalculationNode      1       - LET #8 = (constituent.`quantity`.`value` < 0)   /* simple expression */
  7   FilterNode           1       - FILTER #8
  8   CalculationNode      1       - LET #10 = recipe.`_key`   /* attribute expression */
  9   ReturnNode           1       - RETURN #10

但在个人资料中:

Execution plan:
 Id   NodeType          Calls    Items   Runtime [s]   Comment
  1   SingletonNode         1        1       0.00000   * ROOT
  5   TraversalNode       433   432006       7.64893     - FOR recipe  /* vertex */, constituent  /* edge */ IN 1..1  /* min..maxPathDepth */ INBOUND 'ingredients/carrot' /* startnode */  hasConstituent
  6   CalculationNode     433   432006       0.28761       - LET #8 = (constituent.`quantity`.`value` < 0)   /* simple expression */
  7   FilterNode            1        0       0.08704       - FILTER #8
  8   CalculationNode       1        0       0.00000       - LET #10 = recipe.`_key`   /* attribute expression */
  9   ReturnNode            1        0       0.00001       - RETURN #10

我精确地在两个结果中都使用了索引:

Indexes used:
 By   Name              Type         Collection       Unique   Sparse   Selectivity   Fields                        Ranges
  5   recipeByIngrQty   persistent   hasConstituent   false    false       100.00 %   [ `_to`, `quantity.value` ]   base INBOUND

非常欢迎任何帮助

【问题讨论】:

    标签: arangodb


    【解决方案1】:

    对于遍历FOR vertex, edge, path IN ...,过滤vertexedge 仅适用于结果,而不适用于实际访问的内容。至于为什么这样做有意义,请记住,通常,并非遍历期间访问的所有顶点或边实际上都是结果的一部分:例如,如果 IN min..max 参数中的 min 大于零 - 它是一个默认 - 距离小于该距离的顶点(及其传入边)不是结果的一部分,但必须被访问。

    这就是为什么,如果您想在遍历期间限制 访问 的边,则必须改为在 path 变量上添加过滤器。以您为例:

    FOR recipe, constituent, p IN INBOUND 'ingredients/carrot' hasConstituent
        FILTER p.edges[*].quantity.value ALL < 0
        RETURN recipe._key
    

    这应该像您预期的那样使用索引。有关详细信息,请参阅 vertex centric indexesAQL graph traversal 文档。

    我认为这回答了您问题的核心,现在来清理一下您在途中发现的一些问题。

    我希望它按数字顺序对索引进行排序,然后 显着提高 FILTER 或 SORT/LIMIT 请求的速度,但 现在上一个请求需要大约 7.9 秒...如果我使索引“稀疏”, 它需要与没有索引相同的时间(~3.9s)

    这里有两件事。

    首先,听起来优化器更喜欢您的索引而不是边缘索引。情况可能不应该是这样,因为(没有我上面描述的更改)它并不比边缘索引更具体,只是稍微慢一些。您还没有指定您使用的 ArangoDB 版本,所以我无法具体评论。但是,如果您使用的是受支持的次要版本的最新补丁版本,例如3.7.10 或 3.6.12 在撰写本文时,您可以将其报告为 issue on Github

    其次,稀疏索引不会索引不存在或null 的值。因此它不能用于可以报告null 值的查询。现在请注意null &lt; 0true,有关详细信息,请参阅文档中的type and value order。因此,您的查询 constituent.quantity.value &lt; 0 可以报告 null 值,这就是稀疏索引被区别对待的原因(即根本不能使用)。

    现在到最后一点:

    最难理解的是explain结果给出的执行计划与profile结果不同。

    解释输出显示一列“Est.”,这是该节点将发出/执行的行数/迭代数的估计值。相反,配置文件输出中的“项目”列是相应的确切数字。现在这个估计在某些情况下可能很好,但在其他情况下很差。这不一定是问题,如果不实际执行查询,它就不可能准确。如果它碰巧导致问题,因为估计让优化器为作业选择了错误的索引,你可以使用index hints。但这里不是这样。

    除此之外,您展示的两个计划似乎完全相同。

    【讨论】:

      猜你喜欢
      • 2015-07-12
      • 2014-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多