如何提高Xquery循环转换的性能

如何提高Xquery循环转换的性能,xquery,marklogic,Xquery,Marklogic,我在Xquery中使用了一种特殊的方法,如下所示 declare function ctrlv($node, $node-id as xs:string) { <z:b> { (attribute {"xml:id"}{$node/@xml:id}) }</z:b> }; 声明函数ctrlv($node,$node id为xs:string) { { (属性{“xml:id”}{$node/@xml:id}) } };

我在Xquery中使用了一种特殊的方法,如下所示

declare function ctrlv($node, $node-id as xs:string) 
{
    <z:b> 
    {
        (attribute {"xml:id"}{$node/@xml:id})
      }</z:b>
};
声明函数ctrlv($node,$node id为xs:string)
{
{
(属性{“xml:id”}{$node/@xml:id})
}
};
此特定函数使用diff$节点循环11000次。仅给出的方法就占用了整个响应时间的50-60%(约8秒)。当我执行性能评测时,它显示$node/@xml:id花费的时间最长。
在这种情况下,如何提高性能?请提供帮助

我不太清楚为什么要使用从
$node
获得的相同名称构造一个新属性,并插入
@id
的值。由于使用元素的构造应该会有一些开销,我想下面的方法会更快(并且应该提供相同的输出):

声明函数ctrlv($node,$node id为xs:string)
{
{$node/@xml:id}
};

另外,
$node id
从未在函数中使用,因此您可能希望将其作为参数删除。

有一些增量步骤可以提高这些操作的速度。创建XML元素有点贵(虽然.3毫秒没那么糟糕……但是如果你做了10万个元素,它就加起来了)

以下是确定最常用表达式的一些步骤。 它们是在确定性能问题后,而不是在, 因为在大多数情况下,性能影响最小,代码可读性和可维护性更为重要。但是一旦你确定了一个热点,考虑这些:

限制函数调用—这种简单的操作可以在没有函数的情况下内联完成。 限制对变量的绑定 循环的极限 限制元素和属性的动态构造

当然,你不能做所有这些,但你可以决定哪里最痛苦,并在那里应用这些概念。 例如,上面的调用可以内联为

<z:b xml:id="{$node/@xml:id}"/>

尝试将此内联放置在尝试函数的位置,然后查看结果


还请注意,探查器有时会提供误导性信息。许多表达式都是惰性计算的,并且倾向于将它们的时间归因于它们的使用位置,而不是它们的声明位置。

如果要使用相同的uri将修改后的文档写回数据库,请尝试使用xdmp:node-replace()函数修改属性值,而不是在内存中构建新的文档树并将其写回数据库


如果没有,循环中会发生什么?您是在每次迭代中构造一个新文档,还是迭代器使用类型开关在树上递归,构造新属性及其祖先元素,但复制所有其他节点?

您的计算机速度特别慢吗?探查器告诉我,这将在250毫秒内运行

declare function local:do($node) 
{
  element b { $node/@xml:id }
};

distinct-values(
  (1 to 10 * 1000) ! local:do(<test xml:id="a123"/>))
声明函数本地:do($node)
{
元素b{$node/@xml:id}
};
不同的价值观(
(1到10*1000)!本地:do())

另一个尝试是XSLT实现。您仍然需要计算
$node/@xml:id
11000次,但得到该表达式的速度要快一些。

您好,谢谢您的回复。我试过你建议的方法。这没有任何改善。基本上,我从数据库中获取一个大型xml,并循环通过每个节点转换为不同的输出结构。请给我推荐一些性能好的选择。注意:xml可能有很多级别的子元素,那么您的问题只是访问属性,这当然需要一些时间。索引总是能加速数据库世界中的事情,所以请看一下它们。Marklogic会自动为属性编制索引,因此实际上应该已经应用了它。查看
xdmp:plan
,查看实际使用索引时的查询计划。但你也必须接受一个事实,那就是这可能需要一些时间。在大约4秒内执行该查询11000次意味着每次执行大约需要0.36毫秒。这一切都将发生在内存中,因此无需查看索引。任何索引查找都发生在这一点之前很久。
declare function local:do($node) 
{
  element b { $node/@xml:id }
};

distinct-values(
  (1 to 10 * 1000) ! local:do(<test xml:id="a123"/>))