Прежде всего, лучший способ оптимизировать запросы в eXist - хранить XML локально и с индексами. Пожалуйста, используйте встроенную документацию для настройки индексов.
Однако ваш код страдает от повторной загрузки одних и тех же данных из сети. Давайте позаботимся об этой и другой проблеме, о вашем использовании XML-запросов в памяти, о другом узком месте оптимизации.
Важнейшим первым шагом является предоставление XML-запроса в локальной базе данных. Запросы узлов в базе данных быстрее и меньше памяти, чем запросы к узлам XML в памяти. (По крайней мере, это был тот случай с версиями до 2.2.)
Итак, вот способ кэширования данных локально, обновляя кеш после последнего обновления более 5 минут.
xquery version "3.0";
declare namespace bus="http://docs.gijon.es/sw/busgijon.asmx";
(: Store the XML data in the collection /db/busgijon/data :)
declare variable $COL := "/db/busgijon/data";
declare variable $INFO-FILE := "busgijoninfo.xml";
declare variable $TR-FILE := "busgijontr.xml";
(: Fetch a page from cache or from web site, updating the cache :)
declare function local:fetchPage($filename) {
(: If the page was fetched more than 5 minutes ago, refresh it :)
let $expire := current-dateTime() - xs:dayTimeDuration('PT5M')
let $page := doc($COL || "/" || $filename)/page
return if (exists($page))
then if ($page/xs:dateTime(@timestamp) ge $expire)
then $page
else (update replace $page/* with doc("http://datos.gijon.es/doc/transporte/" || $filename)/*
, update value $page/@timestamp with current-dateTime()
, $page)
else doc(xmldb:store($COL, $filename, <page timestamp="{current-dateTime()}">{doc("http://datos.gijon.es/doc/transporte/" || $filename)/*}</page>))/page
};
declare function local:getBusesPorLinea($linea)
{
(: Get the two pages from the database cache for querying :)
let $info := local:fetchPage($INFO-FILE)/bus:BusGijonInfo
let $tr := local:fetchPage($TR-FILE)/bus:BusGijonTr
let $numero:=$linea
let $nBuses:=count($tr//bus:llegada[bus:idlinea=$numero])
return
if($nBuses=0)
then(<p>No hay ningun bus en esta linea</p>)
else(
<div>
<h2>Numero de buses funcionando en la linea {$numero} : {$nBuses}</h2>
<table class="table table-hover">
<thead>
<tr>
<th>Parada</th>
<th>Minutos hasta la llegada</th>
</tr>
</thead>
<tbody>
{
(: Loop through the TR page - fetched just once from cache :)
for $l in $tr//bus:llegada[bus:idlinea=$numero]
(: Loop through the Info page - fetched just once from cache :)
for $parada in $info//paradas/bus:parada[bus:idparada=$l/bus:idparada]
return <tr>
<td>{$parada/bus:descripcion}</td>
<td>{$l/bus:minutos}</td></tr>
}
</tbody>
</table>
</div>
)
};
local:getBusesPorLinea(1)
Единственная часть, что я изменил в локальной: функция getBusesPorLinea была выборка два документа в верхней части из кэша и те, которые находятся на встроенных шлейфов.
Местный: функция fetchPage - это место, где происходит большая часть ускорения. Вот что он делает:
- Установите срок действия до 5 минут в прошлом.
- Попробуйте извлечь указанную страницу из кеша.
- Если страница существует, сравните выбранную временную метку с меткой истечения срока годности.
- Если метка времени страницы меньше 5 минут назад (больше, чем временная метка истечения срока действия), верните эту страницу.
- Если временная метка страницы больше 5 минут назад, обновите ее, обновите содержимое страницы с обновленным документом, обновите временную метку страницы и верните новую страницу.
- Если страница еще не существует, сохраните страницу в указанной коллекции с текущей меткой времени, возвращая элемент страницы.
Первый человек, получивший доступ к этому XQuery через 5 минут, будет иметь дополнительные 5-10 секунд после обновления кеша. Это позволяет кэшу быть пассивным, поэтому вам не нужно вручную обновлять его каждые пять минут.
Надеюсь, это поможет.
Просто примечание стороны, что сказал Майкл Кей еще самое непосредственное отношение: Старайтесь избегать '' // проблем с производительностью, если вы имеете. Это всегда должно вызвать полное сканирование всех потомков, и конкретный поиск (т. Е. С полным путем), безусловно, будет быстрее. – dirkk
@ dirkk На самом деле это не так для eXist. Скорее обратное верно, т. Е. '//' может быть намного быстрее, чем использование полного пути из-за того, как работает индексация; Это предполагает, что вы сначала создали индексы ;-) – adamretter
@adamretter Интересно, я этого не знал. Я также удивлен, потому что конкретный путь всегда имеет больше информации, чем простой оператор-потомок-сам, т. Е. Оптимизатор может (теоретически) переписать конкретный путь к '//', тогда как это невозможно по-другому. Но я буду воздерживаться от этого утверждения в будущем для общего процессора XQuery, похоже, что это справедливо только для BaseX. – dirkk