欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

AQL]FOR 操作

最编程 2024-07-15 13:44:17
...

FOR operation in AQL

目录

  • FOR 操作
    • 语法
    • 使用
    • Optional
      • indexHint
      • forceIndexHint
      • disableIndex
      • maxProjections
      • useCache
      • lookahead

FOR 操作

通用的FOR操作可以遍历集合或视图、数组的元素或遍历图

语法

1、在集合和数组上迭代的通用语法是:

FOR variableName IN expression

2、图遍历还有一个特殊的变体

FOR vertexVariableName [, edgeVariableName [, pathVariableName ] ] IN traversalExpression

3、对于“视图”,有一个特殊(可选)的SEARCH关键字

FOR variableName IN viewName SEARCH searchExpression

在遍历中视图不能用作边集合:

FOR v IN 1..3 ANY startVertex viewName /* invalid! */

所有变体都可以选择在结尾处使用OPTIONS{…}子句。

使用

表达式返回的每个数组元素只访问一次。要求表达式在所有情况下都返回一个数组。空数组也是允许的。当前数组元素可在variableName指定的变量中进行进一步处理。

FOR u IN users
  RETURN u

这将迭代users数组的所有元素(在这个例子中,数组 users 包含了从名为“users”的集合中获取的所有文档对象)。在遍历过程中,对于数组中的每一个元素(即集合中的每一条记录),都将该元素的值赋予变量 u。在此示例中并没有对变量 u 进行任何修改操作,而是通过 RETURN 关键字将其原封不动地添加到结果集中。

注意:当像这里所示那样遍历基于集合的数组时,如果不使用 SORT 语句明确定义排序顺序,则文档的排列顺序是不确定的。

FOR引入的变量在FOR所在的范围关闭之前一直可用。

另一个使用静态声明的值数组进行迭代的示例:

FOR year IN [ 2011, 2012, 2013 ]
  RETURN { "year" : year, "isLeapYear" : year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) }

嵌套使用多个FOR循环也是允许的。当FOR循环进行嵌套时,各个独立FOR循环返回的数组元素将生成一个笛卡尔积(cross product)。这意味着每个内部循环的每次迭代都会与外部循环的所有可能值组合,从而创建出所有可能的组合结果

FOR u IN users
  FOR l IN locations
    RETURN { "user" : u, "location" : l }

在这个例子中,外部循环遍历users数组的每个用户元素,并在每次迭代时将当前用户赋值给变量u。内部循环则对应于locations数组,它会为users数组中的每一个用户元素遍历一遍所有的地点。
因此,如果users数组有3个用户,而locations数组有4个地点,则总共会产生3(来自用户数组)乘以4(来自地点数组)共12次迭代。在每次内部循环迭代时,都会使用当前用户的值(存储在u中)和当前地点的值(存储在l中),进行进一步的处理或计算

另请参阅将查询与子查询组合

Optional

对于集合和视图,For构造支持一个可选的OPTIONS子句来修改行为。一般语法如下:

FOR variableName IN expression OPTIONS { option: value, ... }

indexHint

对于集合,可以使用indexHint选项向优化器提供索引提示。该值可以是单个索引名称,也可以是按首选项顺序排列的索引名称列表:

FOR … IN … OPTIONS { indexHint: "byName" }
FOR … IN … OPTIONS { indexHint: ["byName", "byColor"] }

在执行FOR循环时,如果有机会使用索引来提高查询性能,优化器会首先检查指定的索引是否可以被利用。当提供的是一个索引数组时,优化器将按照指定的顺序依次检查每个索引的可行性。

无论正常情况下它会选择哪个索引,优化器都会优先选择并使用第一个适用的索引。这意味着,在有多重索引可供选择的情况下,优化器不会去寻找最优解,而是直接采用列表中首个满足条件的索引来加速查询过程。这种策略简化了优化步骤,并确保了查询处理的确定性。

如果指定的索引中没有一个适合当前查询条件,那么优化器将会退回到其正常的逻辑处理方式,即自动选择另一个可能适用的索引。如果启用了强制索引提示(forceIndexHint),并且所有指定的索引都不适用,则查询会失败,因为在这种情况下,系统被要求必须使用指定的索引进行查询优化,而无法找到合适的索引会导致操作无法执行。

forceIndexHint

默认情况下,索引提示(Index hints)并不会被强制执行。如果设置了 forceIndexHinttrue,则当 indexHint 提供的索引不可用时,系统将会抛出错误,而不是选择回退至其他可用索引或者完全不使用索引进行查询操作。

FOR … IN … OPTIONS { indexHint: … , forceIndexHint: true }

这意味着在启用 forceIndexHint 的情况下,数据库优化器必须按照提供的 indexHint 中指定的索引进行查询处理。若指定的索引不适合当前查询或不存在,查询将无法执行并返回错误信息。这一设置通常用于确保特定索引策略得到严格遵循,尤其是在调试、性能测试或对查询行为有特殊要求的情况下。

disableIndex

引入于:v3.9.1

在某些罕见的情况下,不使用索引查找或扫描而是进行全集合扫描可能更有利。如果索引查找产生了大量(甚至是所有文档)并且仅通过索引数据无法满足查询需求,那么索引查找的成本可能会高于全集合扫描。

解释:在索引查找过程中,虽然可以快速定位到相关文档,但如果需要返回的结果占整个集合的很大比例或者几乎全部时,数据库系统可能需要额外加载主键值以获取完整文档信息,并且多次磁盘I/O操作会增加开销。相比之下,执行全集合扫描虽然一次性读取的数据量较大,但在某些情况下反而能够更高效地完成查询任务。因此,数据库优化器会根据实际查询条件和数据分布情况来决定是否使用索引还是进行全表扫描。

考虑以下查询语句以及在value属性上存在的索引:

FOR doc IN collection 
  FILTER doc.value <= 99 
  RETURN doc.other

在这个案例中,优化器可能会选择使用value属性上的索引,因为它能够覆盖查询的FILTER条件。然而,在满足FILTER条件的每个索引值基础上,为了返回other属性的值,查询必须额外查找相应的文档。如果索引条目数量很大(接近或等于集合中的文档总数),那么在这种情况下使用索引可能反而会导致比直接扫描整个集合更多的工作量。

这是因为,即使利用了索引快速定位到符合条件的记录,对于每一个通过FILTER条件的索引值,仍然需要执行一次回表操作以获取完整的文档数据。当大部分或者全部文档都满足筛选条件时,这种频繁的回表操作可能会超过对整个集合进行顺序扫描的成本。因此,在某些特定场景下,全表扫描可能是更优的选择。

在某些情况下,尽管最终结果表明索引扫描可能比全集合扫描更慢,但优化器通常仍然会选择优先考虑使用索引扫描。这是因为索引扫描有助于快速定位到符合条件的数据,减少不必要的数据读取。

然而,如果你想强制优化器在特定的FOR循环中不使用任何索引,可以通过设置查询提示(hint)来实现这一点。例如,在一些数据库系统中,可以使用类似disableIndex的提示,并将其设置为true:

FOR doc IN collection OPTIONS { disableIndex: true }
  FILTER doc.value <= 99
  RETURN doc.other

使用 disableIndex: false 对于地理索引(geo indexes)或全文索引(fulltext indexes)并无影响,因为这些类型的索引在特定查询条件下通常是必须使用的。

另外请注意,如果同时设置了 disableIndex: true 和 indexHint,那么这种设置是含糊不清的。在这种情况下,优化器将始终优先遵循 disableIndex 提示。这意味着即便你试图通过 indexHint 强制指定使用某个索引,只要 disableIndex 设置为 true,优化器仍然会避免使用任何索引并执行全集合扫描操作。

maxProjections

引入于:v3.9.1

默认情况下,查询优化器在处理FOR循环时,会考虑最多使用5个文档属性作为投影(projection)。如果在一个FOR循环中访问了集合中超过5个属性,优化器将倾向于提取完整的文档而非使用投影

这意味着,在执行查询时,若需要从每个文档中获取少量属性(5个或更少),优化器会选择只读取所需的那些属性,从而减少数据传输量和提高查询性能。但当查询涉及的属性数量超过这个阈值时,为了简化处理逻辑,优化器可能决定直接加载整个文档内容,而不是进行复杂的投影操作。这种策略有助于保证查询效率,尤其是在复杂查询场景下,避免因过于精细的投影导致额外的开销。

这个5个属性的阈值是人为设定的,并可以通过使用maxProjections提示来进行调整。默认情况下,maxProjections的值设置为5,这与之前硬编码的默认值保持一致。

例如,若使用 maxProjections 提示设置为 7,则在以下查询中,优化器将会从原始文档中提取7个属性作为投影:

FOR doc IN collection OPTIONS { maxProjections: 7 } 
  RETURN [ doc.val1, doc.val2, doc.val3, doc.val4, doc.val5, doc.val6, doc.val7 ]

通常情况下,无需调整maxProjections的值,但在某些特定场景下对其进行调整是有意义的:

  1. 当从非常大的文档中提取许多小属性时,增加maxProjections的值可能是有益的。在这种情况下,如果能避免完整复制整个文档,则可以显著减少内存和网络传输开销。

  2. 如果投影操作的成本(如CPU计算和内存分配)高于完整复制较小文档的成本,在这种情况下,降低maxProjections以避免使用投影可能更为合理。对于极其小的文档,直接读取完整内容可能会更快、更高效。

总的来说,调整maxProjections阈值主要依据查询的具体需求以及数据集的特点来决定,旨在优化查询性能并减少不必要的资源消耗。

从3.10版本开始,maxProjections可以用于图形遍历(仅限Enterprise Edition)。

useCache

引入于:v3.9.1

对于启用内存缓存的持久化索引,你可以根据具体情况选择禁用这些内存缓存。这一功能在处理查询时非常有用,特别是当访问启用了内存缓存的索引时,但已知使用缓存会对性能产生负面影响的情况。在这种情况下,你可以设置useCache提示为false:

FOR doc IN collection OPTIONS { useCache: false }
  FILTER doc.value == @value
  ...

你可以在每个FOR循环中单独设置这个提示。如果不显式设置useCache提示,它将默认为启用(true)
这个提示仅针对使用了索引且该索引启用了内存缓存的FOR循环有效。对于以下几种情况,useCache提示不会产生任何效果:

  1. 不使用索引的FOR循环。
  2. 访问未启用内存缓存的索引的FOR循环。
  3. 查询条件中不包含与所有索引属性相等查找(equality lookups)的查询,即使存在内存缓存也无法使用。
  4. 对视图进行迭代操作或执行图形遍历的FOR操作。

在上述情况下,设置useCache提示并不会改变查询行为或者性能表现。

参考Caching of index values.

lookahead

多维索引类型zkd(ZKD,Zero-Knowledge Dictionary)支持一个可选的索引提示来优化性能:

FOR … IN … OPTIONS { lookahead: 32 }

在ArangoDB等数据库系统中,ZKD索引是一种高效的多维索引结构,特别适用于处理高维度的数据查询。通过提供特定的索引提示(index hint),可以对ZKD索引进行微调以提升查询性能。

参考See Multi-dimensional indexes.