XQuery分组和聚合函数总是很慢吗?

时间:2010-03-02 20:34:55

标签: optimization xquery

为每条记录选择一个OrderDetailQuantity的简单UnitPrice表。要使用SQL获取每个Order的总值,它就像

一样简单
SELECT OrderID, SUM(UnitPrice*Quantity)
FROM OrderDetail
GROUP BY OrderID

将表格转换为XML文件后,使用XQUERY我可以获得相同的信息

for $orderId in distinct-values(doc('orderDetails.xml')//orderDetails/OrderID)
   let $totalValue := 
      sum(
      for $detail in doc("orderdetails.xml")//OrderDetails[OrderID =$orderId]
         return $detail/Quantity * $detail/UnitPrice
      )
return <order id="{$orderId}" totalValue="{$totalValue}" />

忽略获取此类信息的纯粹愚蠢,是否有更好的方法来编写XQUERY表达式?因为它非常非常慢(我正在使用XMLSpy)。

1 个答案:

答案 0 :(得分:2)

这是XQuery 1.0中的一个主要缺陷,因此在XQuery 1.1中添加了一个group-by子句,它们添加了一个group by子句,因此您的查询将如下所示:

for $orderDetails in doc('orderDetails.xml')//OrderDetails)
let $orderId = $orderDetails/OrderID
let $orderCost = $orderDetails/Quantity * $orderDetails/UnitPrice
group by $orderId
let $totalValue := sum($orderCost)
return <order id="{$orderId}" totalValue="{$totalValue}" />

不幸的是,XQuery 1.1仍然只是一个工作草案,很少有实现可用。

我们的实现(XQSharp)尝试发现您使用的模式并更有效地执行组(这在查询计划中显示为分组)。不幸的是,我们的实现并没有在您的特定情况下发现一个组。

第一个问题是套管差异(“orderdetails.xml”与“orderDetails.xml”,//orderDetails vs //OrderDetails) - 我认为这些只是错别字。

最大的问题是你所写的不是一个琐碎的小组!

除非您使用的模式另有说明,否则静态分析无法确定每个节点只有一个OrderID,而OrderID的雾化值可能有多个项(如果它有一个列表作为其模式类型)。这意味着distinct-values(doc('orderDetails.xml')//orderDetails/OrderID)的静态分析无法确定每个节点只有一个密钥。

为了解决这个问题,您的查询可以写成如下:

for $orderId in distinct-values(doc("orderDetails.xml")/OrderDetails/exactly-one(OrderID/data(.)))
let $totalValue := 
   sum(
      for $detail in doc("orderDetails.xml")/OrderDetails[exactly-one(OrderID/data(.)) = $orderId]
      return $detail/Quantity * $detail/UnitPrice
   )
return <order id="{$orderId}" totalValue="{$totalValue}" />

此查询具有与group-by相同的语义,因此应进行优化。碰巧这仍然没有在XQSharp中对组进行优化,因此我将此作为对我们软件的错误提交。无论XmlSpy是否执行此优化,我都不能说。