在XQuery中,如何避免在分页简单查询中降低性能?

时间:2012-10-08 11:59:37

标签: performance xpath xquery marklogic

我有一个ML数据库,其中包含数万个文档,以及一个查询,它返回这些文档的全部或部分的一些简单计算值。文档计数已经发展到“所有文档”选项不再可靠地运行而没有超时,并且随着文档数量的增长而变得更糟。显而易见的解决方案是客户端应用程序使用其他表单并对结果进行分页。这是一个离线批处理过程,因此整体速度不是问题 - 我们只是希望保持个人请求的合理性。

查询的分页版本非常简单:

declare namespace ns = "http://some.namespace/here"

declare variable $fromCount external;
declare variable $toCount external;

<response> {
  for $doc in fn:doc()/ns:entity[$fromCount to $toCount]
  return
  <doc> omitted for brevity </doc>
} </response>

问题是,在请求的页面所在的文档集中,查询越慢;大概是因为它必须按顺序加载每个文档,检查它是否是正确的类型并迭代直到它找到$fromCount ns:entity s才开始构建响应。

一个问题是数据库中还有其他类型的文档,因此仅使用fn:doc不是一个现实的选项(尽管它们位于不同的目录中,因此xdmp:directory()可能是一个选项;我会调查。)

ns:entity元素目前还没有索引;那会有帮助吗?它始终是文档的根节点,文档非常大,所以我关心索引的大小。此外,此查询的(缓慢部分)对元素的不感兴趣,只是它存在。

我考虑过使用search: api进行内置分页,但对于一个旨在匹配所有文档的查询来说似乎有点过分了。当然可以手动构建search:search()内部构建的查询。

似乎我真正需要的是数据库中某种类型的所有根节点的有效列表。 Marklogic维持这样的事吗?如果不是索引会解决问题吗?


编辑:事实证明我的答案是使用xdmp:directory()选项,因为ML显然存储了所有文档的快速内存列表。不过,如果这个问题的更通用的解决方案,那么它一定会引起人们的兴趣,所以我会在这里留下这个问题。

1 个答案:

答案 0 :(得分:2)

您的分析是正确的:

  

大概是因为它必须按顺序加载每个文档,检查它是否是正确的类型并迭代直到找到$ fromCount ns:entitys才开始构建响应

通常的答案是cts:search加上unfiltered选项。您发现xdmp:directory更快,但即使比例较小,您仍然可以将分页时间测量为O(n)。见http://docs.marklogic.com/guide/performance/unfiltered#chapter - 基本上数据库正在防止返回误报,除非你告诉它不要。

另一种方法可能是使用cts:uris及其limit选项,但这可能需要根据起始值而不是页数来管理分页状态。例如,如果第1页上的最后一项是“cat”,则在为下一页调用cts:uris时,您将使用“cat”作为arg2。您仍然可以使用分页开始 - 停止值。那仍然是O(n) - 但规模要小得多。