Search code examples
xmlxpathxqueryexist-db

Optimize slow query xquery


Right now the query takes around 2 minutes , before I made some changes it took 3:48m.

The xml documents are taken from a web pages , due to it changes each 5m and gives information about the buses in real time.

Could you help me to optimize this query?

xquery version "3.0";
declare namespace bus="http://docs.gijon.es/sw/busgijon.asmx";

declare function local:getNombreParada($numero)
{
    for $parada in doc("http://datos.gijon.es/doc/transporte/busgijoninfo.xml")//paradas/bus:parada
    where $numero=$parada/bus:idparada
    return $parada/bus:descripcion
};

declare function local:getBusesPorLinea($linea)
{

    let $numero:=$linea
    let $nBuses:=count(doc("http://datos.gijon.es/doc/transporte/busgijontr.xml")//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>
            {
            for $l in doc("http://datos.gijon.es/doc/transporte/busgijontr.xml")//bus:llegada[bus:idlinea=$numero]
                for $parada in doc("http://datos.gijon.es/doc/transporte/busgijoninfo.xml")//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)

PD:i am running this in exist Db


Solution

  • Are documents cached? I'm not an expert, but your code seems to access the same document multiple times. That's OK if you're sure the content is cached in the executing environment. Otherwise I would try to declare

    declare variable $docinfo := doc("http://datos.gijon.es/doc/transporte/busgijoninfo.xml");
    declare variable $doctr   := doc("http://datos.gijon.es/doc/transporte/busgijontr.xml");
    

    to make sure the files are fetched just once.

    You also scan documents at least twice for same kind of data. I would do that once:

    declare variable $paradas  := $docinfo//paradas;
    declare variable $llegadas := $doctr//bus:llegada;
    

    then only filter the collections:

    declare function local:getNombreParada($numero)
    {
        $paradas/bus:parada[bus:idparada = $numero]/bus:descripcion
    };
    
    declare function local:getBusesPorLinea($linea)
    {
        let $numero:=$linea
        let $llegadasNum:=$llegadas[bus:idlinea=$numero]
        let $nBuses:=count($llegadasNum)
    
        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>
                {
                for $l in $llegadasNum
                    for $parada in $paradas/bus:parada[bus:idparada=$l/bus:idparada]
                    return <tr>
                            <td>{$parada/bus:descripcion}</td>
                            <td>{$l/bus:minutos}</td></tr>
                }
            </tbody>
        </table>
    
        </div>
        )
    };
    

    May be that is not much faster, but I hope it is a bit more readable.