优化 GraphQL 查询 optimizing-graphql-queries
提供这些准则是为了帮助防止GraphQL查询出现性能问题。
GraphQL核对清单 graphql-checklist
以下核对清单旨在帮助您在Adobe Experience Manager (AEM)as a Cloud Service中优化GraphQL的配置和使用。
首要原则 first-principles
使用持久GraphQL查询 use-persisted-graphql-queries
推荐
强烈建议使用持久GraphQL查询。
持久的GraphQL查询利用内容交付网络(CDN)帮助降低查询执行性能。 客户端应用程序请求持久查询,GET请求快速边缘启用执行。
进一步引用
请参阅:
安装GraphQL索引包 install-graphql-index-package
推荐
使用GraphQL 的客户必须 安装包含GraphQL索引包的Experience Manager内容片段。 这样,您就可以根据实际使用的功能添加所需的索引定义。 无法安装此包可能会导致GraphQL查询缓慢或失败。
请参阅适用于您的Service Pack的版本的发行说明。 例如,对于最新的Service Pack,请参阅为Experience Manager内容片段安装GraphQL索引包 。
进一步引用
请参阅:
缓存策略 cache-strategy
还可以使用各种缓存方法进行优化。
启用AEM Dispatcher缓存 enable-aem-dispatcher-caching
推荐
AEM Dispatcher是AEM服务中的第一级缓存,在CDN缓存之前。
进一步引用
请参阅:
使用内容交付网络(CDN) use-cdn
推荐
使用CDN时,如果定位为GET
请求,则可以缓存GraphQL查询及其JSON响应。 相比之下,未缓存的请求可能非常(资源)昂贵且处理缓慢,有可能对源头资源造成进一步的有害影响。
进一步引用
请参阅:
设置HTTP缓存控制标头 set-http-cache-control-headers
推荐
在将GraphQL持久查询与CDN结合使用时,建议设置适当的HTTP缓存控制标头。
每个持久查询可以有自己的一组特定的缓存控制标头。 标头可以通过GraphQL API进行设置。
也可以使用 cURL 命令行工具对其进行设置。 例如,使用PUT
请求创建带有缓存控制的打包的简单查询。
$ curl -X PUT \
-H 'authorization: Basic YWRtaW46YWRtaW4=' \
-H "Content-Type: application/json" \
"http://localhost:4502/graphql/persist.json/wknd/plain-article-query-max-age" \
-d \
'{ "query": "{articleList { items { _path author main { json } referencearticle { _path } } } }", "cache-control": { "max-age": 300 }}'
进一步引用
请参阅:
GraphQL查询优化 graphql-query-optimization
在具有大量共享同一模型的内容片段的 AEM 实例上,GraphQL 列表查询的成本可能会较高(就资源而言)。
这是因为 所有 共享将在 GraphQL 查询中使用的模型的片段都必须加载到内存中。这将消耗较多的时间和内存。只能在将整个结果集加载到内存中 后,再应用筛选(它可能会减少最终结果集中的项目数)。
这可能会给人留下一种印象,那就是,即使较小的结果集也会导致性能不佳。然而,实际上这种缓慢是由初始结果集的大小引起的,因为必须先内部处理此情况,之后才能应用筛选。
要减少性能和内存问题,必须使该初始结果集尽可能的小。
AEM 提供了两种方法来优化 GraphQL 查询:
每种方法都有自己的用例和限制。本节提供有关混合过滤和分页的信息,以及一些最佳实践用于优化GraphQL查询的信息。
使用AEM GraphQL混合筛选 use-aem-graphql-hybrid-filtering
推荐
混合筛选结合了 JCR 筛选和 AEM 筛选。
它在将结果集加载到内存中以进行 AEM 筛选之前应用 JCR 筛选(采用查询约束的形式)。这是为了减少加载到内存中的结果集,因为 JCR 筛选会在此之前删除多余的结果。
此技术保留了 GraphQL 筛选提供的灵活性,同时将尽可能多的筛选工作委派给 JCR。
进一步引用
请参阅:
使用GraphQL分页 use-aem-graphql-pagination
推荐
通过使用分页(一种GraphQL标准)将响应分段为块,可以改进具有大型结果集的复杂查询的响应时间。
AEM中的GraphQL支持两种类型的分页:
-
限制/基于偏移的分页
这用于列表查询;这些查询以List
结尾;例如,articleList
。
要使用它,您必须提供要返回的第一个项目的位置 (offset
) 和要返回的项目数(limit
或页面大小)。 -
基于光标的分页(由
first
和after
表示)
这将为每个项目提供一个唯一 ID;也称为光标。
在查询中,您指定上一页的最后一项的光标,以及页面大小(要返回的项目的最大数量)。由于基于光标的分页不适合基于列表的查询的数据结构,因此,AEM 引入了
Paginated
查询类型;例如articlePaginated
。所使用的数据结构和参数遵循 GraphQL 光标连接规范。note note NOTE AEM 目前支持前向分页(使用 after
/first
参数)。后向分页(使用 before
/last
参数)不受支持。
进一步引用
请参阅:
使用GraphQL排序 use-graphql-sorting
推荐
作为GraphQL标准,排序使客户端能够按排序的顺序接收JSON内容。 这可以降低在客户端上执行进一步处理的需要。
仅在所有排序条件都与顶级片段相关时,排序才有效。
如果排序顺序包括某个嵌套片段上的一个或多个字段,则必须将所有共享顶级模型的片段加载到内存中。这会对性能产生负面影响。
进一步引用
请参阅:
最佳实践 best-practices
所有优化推荐的主要目标是减少初始结果集。 此处列出的最佳实践提供了多种方法来实现此目的。可以(也应该)将它们结合使用。
仅筛选顶级属性 filter-top-level-properties-only
目前,JCR 级别的筛选仅适用于顶级片段。
如果筛选处理嵌套片段的字段,则 AEM 必须回退以将所有共享基础模型的片段加载到内存中。
您仍可以使用 AND 运算符将顶级片段字段上的筛选表达式和嵌套片段字段上的筛选表达式组合起来,从而优化此类 GraphQL 查询。
使用内容结构 use-content-structure
在 AEM 中,通常考虑的最佳实践是,使用存储库结构来缩小要处理的内容范围。
此方法也将应用于 GraphQL 查询。
这可以通过在顶级片段的 _path
字段上应用筛选来完成:
{
someList(filter: {
_path: {
_expressions: [
{
value: "/content/dam/some/sub/path/",
_operator: STARTS_WITH
}
]
}
}) {
items {
# ...
}
}
}
value
上的尾随 /
来实现最佳性能。使用分页 use-paging
您还可以使用分页来减小初始结果集;特别是在您的请求不使用任何筛选和排序的情况下。
如果您对嵌套片段进行筛选或排序,分页查询可能仍然很慢,因为 AEM 可能仍需要将大量片段加载到内存中。因此,如果将筛选和分页结合使用,请考虑筛选规则(如上所述)。
对于分页,排序同样重要,因为分页的结果始终是已排序的 - 无论是通过显式还是隐式方式。
如果您主要只对检索前几页感兴趣,则使用 ...List
或 ...Paginated
查询之间没有显著区别。不过,如果您的应用程序不只是想阅读一两页,则应考虑 ...Paginated
查询,因为此查询在阅读后续页面时的性能更佳。
筛选表达式中的逻辑运算 logical-operations-in-filter-expressions
如果在嵌套片段上进行筛选,则仍可以通过提供使用 AND
运算符的顶级字段的附加筛选来利用 JCR 筛选。
一个典型用例是,对顶级片段的 _path
字段使用筛选器来限制查询的范围,然后筛选可能位于顶级或嵌套片段上的其他字段。
在此示例中,将使用 AND
组合不同的筛选表达式。因此,对 _path
进行筛选可以有效地限制初始结果集的大小。对顶级字段进行的所有其他筛选也可以帮助减小初始结果集 - 前提是使用 AND
将它们组合使用。
如果涉及嵌套的片段,则无法优化使用 OR
组合使用的筛选表达式。仅在 不 涉及嵌套片段的情况下,可以优化 OR
表达式。
避免筛选多行文本字段 avoid-filtering-multiline-textfields
无法通过 JCR 查询筛选多行文本字段的字段(html、markdown、plaintext、json),因为必须即时计算这些字段的内容。
如果您仍需要筛选多行文本字段,请考虑通过添加额外的筛选表达式来限制初始结果集的大小,并使用 AND
将它们组合使用。通过筛选 _path
字段来限制范围也是一个好方法。
避免筛选虚拟字段 avoid-filtering-virtual-fields
虚拟字段(大多数字段以 _
开始)是在执行 GraphQL 查询时计算的,因此不在基于 JCR 的筛选的范围内。
一个重要的例外是 _path
字段,可使用该字段有效地减小初始结果集 - 如果相应地构建了内容(请参阅使用内容结构)。
筛选:排除 filtering-exclusions
还存在几种无法在 JCR 级别计算筛选表达式的情况(因此,应避免这些情况以实现最佳性能):
-
使用
_sensitiveness
筛选选项的基于Float
值的筛选表达式,其中_sensitiveness
设置为0.0
之外的任何值。 -
使用
_ignoreCase
筛选选项的基于String
值的筛选表达式。 -
基于
null
值的筛选。 -
使用
_apply: ALL_OR_EMPTY
的基于数组的筛选。 -
使用
_apply: INSTANCES
和_instances: 0
的基于数组的筛选。 -
使用
CONTAINS_NOT
运算符的筛选表达式。 -
使用
NOT_AT
运算符的基于Calendar
、Date
或Time
值的筛选表达式。
最小化内容片段嵌套 minimize-content-fragment-nesting
嵌套内容片段是生成自定义内容结构模型的好方法。 您甚至可以具有一个带有嵌套片段的片段,该片段具有一个嵌套片段,该片段具有……等等。
但是,如果创建的结构级别过多,可能会增加GraphQL查询的处理时间,因为GraphQL必须遍历所有嵌套内容片段的整个层次结构。
深度嵌套还会对内容治理产生不利影响。 一般情况下,建议将内容片段嵌套限制在五或六个级别以下。
不输出所有格式(多行文本元素) do-not-output-all-formats
AEM GraphQL可以返回在 多行文本 数据类型中创作的文本,该文本具有多种格式:富文本、简单文本和Markdown。
输出所有三种格式会将JSON中文本输出的大小增大三倍。 再加上来自非常宽泛查询的通常较大的结果集,可能会产生非常大的JSON响应,因此需要很长时间才能计算。 最好将输出限制为仅呈现内容所需的文本格式。
修改内容片段 modifying-content-fragments
使用AEM UI或API仅修改内容片段及其资源。 请勿直接在JCR中进行修改。
测试查询 test-your-queries
处理GraphQL查询与处理搜索查询类似,并且比简单的包含所有内容的GETAPI请求要复杂得多。
在生产中使用时,在受控的非生产环境中仔细规划、测试和优化查询是以后取得成功的关键。