Всегда ли медленны функции группировки и агрегирования XQuery? - PullRequest
2 голосов
/ 02 марта 2010

Возьмите простую таблицу OrderDetail, в которой для каждой записи есть Quantity и UnitPrice. Чтобы получить общую стоимость каждого ордера с помощью SQL, просто наберите

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 Ответ

2 голосов
/ 12 марта 2010

Это серьезный недостаток в 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 против //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 эту оптимизацию или нет.

...