2010-03-02 42 views
2

取一个简单的OrderDetail表,每个记录有一个QuantityUnitPrice。要获得每个订单与SQL的总价值是简单XQuery分组和聚合函数总是很慢吗?

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)。

回答

2

这是。1.0的一大缺陷,并为此一组-BY子句中XQuery 1.1增加了,他们已经通过条款增加了一个组,所以您的查询应该是这样的:

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”vs“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}" /> 

此查询,则具有相同的语义为一组,通过,并应当在这样的优化。正如它发生的那样,这仍然不能通过XQSharp优化到一个组,所以我已经将它作为一个针对我们的软件的错误提交。无论XmlSpy是否执行此优化,我都不能说。