如何通过Xquery映射优化我的组?

如何通过Xquery映射优化我的组?,xquery,marklogic,Xquery,Marklogic,正在将SQLServer2008R2和MarkLogic8与简单的Person实体进行比较。 我的数据集用于100万条记录/文档。注意:两个数据库位于同一台计算机上(Localhost) 以下SQLServer查询已在闪存中就绪: set statistics time on select top 10 FirstName + ' ' + LastName, count(FirstName + ' ' + LastName) from [Person] group by FirstName

正在将SQLServer2008R2和MarkLogic8与简单的Person实体进行比较。 我的数据集用于100万条记录/文档。注意:两个数据库位于同一台计算机上(Localhost)

以下SQLServer查询已在闪存中就绪:

set statistics time on 

select top 10 FirstName + ' ' + LastName, count(FirstName + ' ' + LastName)
from [Person]
group by FirstName + ' ' + LastName
order by count(FirstName + ' ' + LastName) desc

set statistics time off
结果是:

Richard Petter  421
Mark Petter 404
Erik Petter 400
Arjan Petter    239
Erik Wind   237
Jordi Petter    235
Richard Hilbrink    234
Mark Dominee    234
Richard De Boer 233
Erik Bakker 233

SQL Server Execution Times:
  CPU time = 717 ms,  elapsed time = 198 ms.
Richard Petter => 421
Mark Petter => 404
Erik Petter => 400
Arjan Petter => 239
Erik Wind => 237
Jordi Petter => 235
Mark Dominee => 234
Richard Hilbrink => 234
Erik Bakker => 233
Richard De Boer => 233

elapsed-time:PT42.797S
但是,MarkLogic 8上的XQuery要慢得多:

(                               
  let $m := map:map()
  let $build :=
    for $person in collection('/collections/Persons')/Person
    let $pname := $person/concat(FirstName/text(), ' ', LastName/text())
    return map:put(
      $m, $pname, sum((
        map:get($m, $pname), 1)))
  for $pname in map:keys($m)
  order by map:get($m, $pname) descending
  return
    concat($pname, ' => ', map:get($m, $pname))
)[1 to 10]
, 
xdmp:query-meters()/qm:elapsed-time
结果是:

Richard Petter  421
Mark Petter 404
Erik Petter 400
Arjan Petter    239
Erik Wind   237
Jordi Petter    235
Richard Hilbrink    234
Mark Dominee    234
Richard De Boer 233
Erik Bakker 233

SQL Server Execution Times:
  CPU time = 717 ms,  elapsed time = 198 ms.
Richard Petter => 421
Mark Petter => 404
Erik Petter => 400
Arjan Petter => 239
Erik Wind => 237
Jordi Petter => 235
Mark Dominee => 234
Richard Hilbrink => 234
Erik Bakker => 233
Richard De Boer => 233

elapsed-time:PT42.797S
在我看来,198毫秒与42秒的差距很大。 XQuery根据本指南使用地图进行分组:

我有两个问题:

  • XQuery是否可以通过任何方式进行调优以获得更好的性能
  • 带有group by的XQuery 3.0是否已在MarkLogic 8上可用

谢谢你的帮助

首先,是的,有很多方法可以优化MarkLogic中的查询。一个明显的方法是使用范围索引;但是,我强烈建议首先阅读他们关于该主题的文档:

为了更高层次地了解数据库体系结构,有一份名为Inside Marklogic Server的白皮书详细解释了该设计:

关于
groupby
,MarkLogic可能有人想正式发表评论,但据我所知,他们的立场是不可能建立一个普遍高性能的
groupby
,因此他们选择不实施它。这使得开发人员有责任了解编写快速查询的最佳实践


特别是在您的示例中,Mike Blakeley基于地图的分组模式不太可能是问题所在。有几种不同的方法可以分析ML中的查询,其中任何一种都可以引导您找到任何热点。我的猜测是,获取
Person
数据的IO开销是问题所在。解决这一问题的一种常见方法是为
FirstName
LastName
配置范围索引,并使用
cts:value tuples
从范围索引中同时查询它们,这将避免不在缓存中的每个文档都进入磁盘。

正如@wst所说,您当前的实现面临的挑战是,它加载所有文档以提取名字和姓氏,将它们逐个相加,然后报告前十名。而不是这样做,您将希望使用索引

假设在FirstName和LastName上设置了字符串范围索引。在这种情况下,您可以运行以下命令:

xquery version "1.0-ml";

for $co in 
  cts:element-value-co-occurrences(
    xs:QName("FirstName"), 
    xs:QName("LastName"), 
    ("frequency-order", "limit=10"))
return
  $co/cts:value[1] || ' ' || $co/cts:value[2] || ' => ' || cts:frequency($co)

它使用索引查找同一文档中的名字和姓氏。cts:频率表示同时发生的频率。这都是索引驱动的,所以速度会非常快

两个答案都是相关的。但从你的要求来看,大卫·C的答案最接近你想要的。但是,这个答案假设您需要找到名字和姓氏的组合

如果您的文档有一个标识uniq字段(考虑主键),那么:

    • 在该字段上放置范围索引
    • 使用cts:元素值 ---选项:(片段频率、频率顺序、即时、并发、限制=10)
  • -计数来自cts:频率
  • -然后使用生成的10个ID获取名称信息
  • 如果唯一ID字段可以是整数,那么初始搜索的速度也会快很多倍

    和。。也可以使用我的步骤1-2立即获得Id列表,并将其用作David C答案的限制条件-使用“查询”选项中Id的元素值范围查询。这使您不必像我的选择那样自己创建名称,并可能加快David C的方法

    这个故事的寓意是——如果不首先调整数据库的性能(索引)并使用特定的查询(范围查询、共现等),那么结果就没有任何意义

    故事的寓意-第2部分:许多方法-所有相关的和可行的。细微的差异-所有这些都取决于您的具体数据

    该文件列在下面


    此外,对于更复杂的分组查询,您可能希望使用为MarkLogic编写的库