2010-03-02 10 views
2

Prenez une table simple OrderDetail qui a un Quantity et UnitPrice pour chaque enregistrement. Pour obtenir la valeur totale de chaque commande avec SQL, il est simple commeLes fonctions de regroupement et d'agrégation XQuery sont-elles toujours lentes?

SELECT OrderID, SUM(UnitPrice*Quantity) 
FROM OrderDetail 
GROUP BY OrderID 

Après conversion de la table dans un fichier XML, en utilisant XQuery Je suis en mesure d'obtenir les mêmes informations que ce

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}" /> 

Ignorer la pure stupidité d'obtenir l'information comme ceci, y at-il une meilleure façon d'écrire l'expression XQUERY? Comme c'est très, très lent (j'utilise XMLSpy).

Répondre

2

Ceci est un défaut majeur dans XQuery 1.0, et pour cette raison un groupe par clause a été ajoutée dans XQuery 1.1, ils ont ajouté un groupe par article, de sorte que votre requête ressemblerait à ceci:

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}" /> 

Malheureusement, XQuery 1.1 n'est encore qu'un brouillon de travail et peu d'implémentations sont disponibles.

Notre implémentation (XQSharp) essaye de repérer le motif que vous avez utilisé et de faire le groupe plus efficacement (cela apparaît comme un group-by dans le plan de requête). Malheureusement, notre implémentation ne repère pas un groupe dans votre cas particulier.

Le premier problème est différences de boîtier ("orderdetails.xml" vs "orderDetails.xml", //orderDetails vs //OrderDetails) - Je suppose que ce ne sont que des fautes de frappe.

Le plus gros problème est que ce que vous avez écrit n'est pas un groupe trivial! Sauf si vous utilisez un schéma qui indique le contraire, l'analyse statique ne peut pas déterminer que chaque nœud a exactement un OrderID, et la valeur atomisée de OrderID peut avoir plus d'un élément (s'il a une liste comme type de schéma). Cela signifie que l'analyse statique de distinct-values(doc('orderDetails.xml')//orderDetails/OrderID) ne peut pas déterminer que chaque nœud a exactement une clé.

Pour résoudre ce votre requête peut être écrite comme suit:

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}" /> 

Cette requête a alors la même sémantique en tant que groupe par et doit être optimisé en tant que tel. En l'occurrence, cela ne fonctionne toujours pas dans un groupe de XQSharp, donc j'ai classé cela comme un bug contre notre logiciel. Que XmlSpy effectue cette optimisation ou non, je ne pourrais pas dire.