2015-06-16 3 views
1

После устранения проблемы в следующем Stackoverflow у меня возникла другая проблема, когда я пытаюсь сделать соединение, как показано ниже. Последний запрос занимает около 250 мс, а первые два - только 16 мс. Есть ли лучший способ выполнить соединение между двумя элементами?Оптимизация запросов BaseX при присоединении

Примечание: данные теста можно найти из этого link.

let $PlGeTys := 
    /root/PlGeTys/PlGeTy[ 
    isOfPlCt/@href=/root/PlCts/PlCt[ 
     environment='AIR' 
    ]/@id 
    ] 

let $PlSpTys := 
    /root/PlSpTys/PlSpTy[ 
    isOfPlGeTy/@href=$PlGeTys/@id 
    ] 

for $PlGeTy in $PlGeTys, 
$PlSpTy in $PlSpTys 
where $PlSpTy/isOfPlGeTy/@href=$PlGeTy/@id 
return <done>{$PlGeTy, $PlSpTy }</done> 

Вот информация запроса:

Compiling: 
- applying attribute index for $PlGeTys_0/@*:id 
- rewriting where clause(s) 
Query: 
let $PlGeTys := /root/PlGeTys/PlGeTy[ isOfPlCt/@href=/root/PlCts/PlCt[ environment='AIR' ]/@id ] let $PlSpTys := /root/PlSpTys/PlSpTy[ isOfPlGeTy/@href=$PlGeTys/@id ] for $PlGeTy in $PlGeTys, $PlSpTy in $PlSpTys where $PlSpTy/isOfPlGeTy/@href=$PlGeTy/@id return "done" 
Optimized Query: 
let $PlGeTys_0 := db:open-pre("Output6",0)/*:root/*:PlGeTys/*:PlGeTy[(*:isOfPlCt/@*:href = root()/*:root/*:PlCts/*:PlCt[(*:environment = "AIR")]/@*:id)] let $PlSpTys_1 := db:attribute("Output6", $PlGeTys_0/@*:id)/self::*:href/parent::*:isOfPlGeTy/parent::*:PlSpTy for $PlGeTy_2 in $PlGeTys_0 for $PlSpTy_3 in ($PlSpTys_1)[(isOfPlGeTy/@href = $PlGeTy_2/@*:id)] return "done" 
Result: 
- Hit(s): 3642 Items 
- Updated: 0 Items 
- Printed: 18209 Bytes 
- Read Locking: local [Output6] 
- Write Locking: none 
Timing: 
- Parsing: 0.77 ms 
- Compiling: 0.47 ms 
- Evaluating: 215.71 ms 
- Printing: 0.17 ms 
- Total Time: 217.11 ms 
Query plan: 
<QueryPlan compiled="true"> 
    <GFLWOR> 
    <Let> 
     <Var name="$PlGeTys" id="0"/> 
     <IterPath> 
     <DBNode name="Output6" pre="0"/> 
     <IterStep axis="child" test="*:root"/> 
     <IterStep axis="child" test="*:PlGeTys"/> 
     <IterStep axis="child" test="*:PlGeTy"> 
      <CmpG op="="> 
      <CachedPath> 
       <IterStep axis="child" test="*:isOfPlCt"/> 
       <IterStep axis="attribute" test="*:href"/> 
      </CachedPath> 
      <IterPath> 
       <Root/> 
       <IterStep axis="child" test="*:root"/> 
       <IterStep axis="child" test="*:PlCts"/> 
       <IterStep axis="child" test="*:PlCt"> 
       <CmpG op="="> 
        <CachedPath> 
        <IterStep axis="child" test="*:environment"/> 
        </CachedPath> 
        <Str value="AIR" type="xs:string"/> 
       </CmpG> 
       </IterStep> 
       <IterStep axis="attribute" test="*:id"/> 
      </IterPath> 
      </CmpG> 
     </IterStep> 
     </IterPath> 
    </Let> 
    <Let> 
     <Var name="$PlSpTys" id="1"/> 
     <CachedPath> 
     <ValueAccess data="Output6" type="ATTRIBUTE"> 
      <CachedPath> 
      <VarRef> 
       <Var name="$PlGeTys" id="0"/> 
      </VarRef> 
      <IterStep axis="attribute" test="*:id"/> 
      </CachedPath> 
     </ValueAccess> 
     <IterStep axis="self" test="*:href"/> 
     <IterStep axis="parent" test="*:isOfPlGeTy"/> 
     <IterStep axis="parent" test="*:PlSpTy"/> 
     </CachedPath> 
    </Let> 
    <For> 
     <Var name="$PlGeTy" id="2"/> 
     <VarRef> 
     <Var name="$PlGeTys" id="0"/> 
     </VarRef> 
    </For> 
    <For> 
     <Var name="$PlSpTy" id="3"/> 
     <IterFilter> 
     <VarRef> 
      <Var name="$PlSpTys" id="1"/> 
     </VarRef> 
     <CmpG op="="> 
      <CachedPath> 
      <IterStep axis="child" test="isOfPlGeTy"/> 
      <IterStep axis="attribute" test="href"/> 
      </CachedPath> 
      <IterPath> 
      <VarRef> 
       <Var name="$PlGeTy" id="2"/> 
      </VarRef> 
      <IterStep axis="attribute" test="*:id"/> 
      </IterPath> 
     </CmpG> 
     </IterFilter> 
    </For> 
    <Str value="done" type="xs:string"/> 
    </GFLWOR> 
</QueryPlan> 

Update два:

Вопрос выше фиксирована. Но когда я хочу использовать его в локальной функции, как показано ниже, она занимает около 700 мс. Я делаю что-то неправильно?

declare function local:result($root as element(root)) as element()* { 
    let $PlCts := $root/PlCts/PlCt[environment = 'AIR']/@id 
    for $PlGeTy in $root/PlGeTys/PlGeTy[isOfPlCt/@href = $PlCts], 
     $PlSpTy in $root/PlSpTys/PlSpTy[isOfPlGeTy/@href = $PlGeTy/@id] 
    return <done>{ $PlGeTy, $PlSpTy }</done> 
}; 

let $result := local:result(/root) 
return $result 

Информация о запросе;

Compiling: 
- removing redundant element()* cast. 
- inlining local:result#1 
- inlining $root_5 as element(root) 
- simplifying flwor expression 
Query: 
declare function local:result($root as element(root)) as element()* { let $PlCts := $root/PlCts/PlCt[environment = 'AIR']/@id for $PlGeTy in $root/PlGeTys/PlGeTy[isOfPlCt/@href = $PlCts], $PlSpTy in $root/PlSpTys/PlSpTy[isOfPlGeTy/@href = $PlGeTy/@id] return <done>{ $PlGeTy, $PlSpTy }</done> }; let $result := local:result(/root) return $result 
Optimized Query: 
let $PlCts_6 := ((: element(root), true :) db:open-pre("Output6",0)/*:root)/PlCts/PlCt[(environment = "AIR")]/@id let $result_4 := for $PlGeTy_7 in ((: element(root), true :) db:open-pre("Output6",0)/*:root)/PlGeTys/PlGeTy[(isOfPlCt/@href = $PlCts_6)] for $PlSpTy_8 in ((: element(root), true :) db:open-pre("Output6",0)/*:root)/PlSpTys/PlSpTy[(isOfPlGeTy/@href = $PlGeTy_7/@id)] return element done { (($PlGeTy_7, $PlSpTy_8)) } return $result_4 
Result: 
- Hit(s): 3642 Items 
- Updated: 0 Items 
- Printed: 553 KB 
- Read Locking: local [Output6] 
- Write Locking: none 
Timing: 
- Parsing: 1.41 ms 
- Compiling: 2.9 ms 
- Evaluating: 581.5 ms 
- Printing: 8.34 ms 
- Total Time: 594.15 ms 
Query plan: 
<QueryPlan compiled="true"> 
    <GFLWOR> 
    <Let> 
     <Var name="$PlCts" id="6"/> 
     <IterPath> 
     <TypeCheck type="element(root)" function="true"> 
      <IterPath> 
      <DBNode name="Output6" pre="0"/> 
      <IterStep axis="child" test="*:root"/> 
      </IterPath> 
     </TypeCheck> 
     <IterStep axis="child" test="PlCts"/> 
     <IterStep axis="child" test="PlCt"> 
      <CmpG op="="> 
      <CachedPath> 
       <IterStep axis="child" test="environment"/> 
      </CachedPath> 
      <Str value="AIR" type="xs:string"/> 
      </CmpG> 
     </IterStep> 
     <IterStep axis="attribute" test="id"/> 
     </IterPath> 
    </Let> 
    <Let> 
     <Var name="$result" id="4"/> 
     <GFLWOR> 
     <For> 
      <Var name="$PlGeTy" id="7"/> 
      <IterPath> 
      <TypeCheck type="element(root)" function="true"> 
       <IterPath> 
       <DBNode name="Output6" pre="0"/> 
       <IterStep axis="child" test="*:root"/> 
       </IterPath> 
      </TypeCheck> 
      <IterStep axis="child" test="PlGeTys"/> 
      <IterStep axis="child" test="PlGeTy"> 
       <CmpG op="="> 
       <CachedPath> 
        <IterStep axis="child" test="isOfPlCt"/> 
        <IterStep axis="attribute" test="href"/> 
       </CachedPath> 
       <VarRef> 
        <Var name="$PlCts" id="6"/> 
       </VarRef> 
       </CmpG> 
      </IterStep> 
      </IterPath> 
     </For> 
     <For> 
      <Var name="$PlSpTy" id="8"/> 
      <IterPath> 
      <TypeCheck type="element(root)" function="true"> 
       <IterPath> 
       <DBNode name="Output6" pre="0"/> 
       <IterStep axis="child" test="*:root"/> 
       </IterPath> 
      </TypeCheck> 
      <IterStep axis="child" test="PlSpTys"/> 
      <IterStep axis="child" test="PlSpTy"> 
       <CmpG op="="> 
       <CachedPath> 
        <IterStep axis="child" test="isOfPlGeTy"/> 
        <IterStep axis="attribute" test="href"/> 
       </CachedPath> 
       <IterPath> 
        <VarRef> 
        <Var name="$PlGeTy" id="7"/> 
        </VarRef> 
        <IterStep axis="attribute" test="id"/> 
       </IterPath> 
       </CmpG> 
      </IterStep> 
      </IterPath> 
     </For> 
     <CElem> 
      <QNm value="done" type="xs:QName"/> 
      <List> 
      <VarRef> 
       <Var name="$PlGeTy" id="7"/> 
      </VarRef> 
      <VarRef> 
       <Var name="$PlSpTy" id="8"/> 
      </VarRef> 
      </List> 
     </CElem> 
     </GFLWOR> 
    </Let> 
    <VarRef> 
     <Var name="$result" id="4"/> 
    </VarRef> 
    </GFLWOR> 
</QueryPlan> 

Update три: Теперь у меня есть еще один вопрос, когда я продлить запрос с дополнительными пунктами «CONT», выполнение запроса длится около 600 мс. Но без элементов «Cont» требуется всего 35 мс. Есть ли у вас предложение по оптимизации этого запроса?

let $PlCts := /root/PlCts/PlCt[environment = 'AIR']/@id 

for $PlGeTy in /root/PlGeTys/PlGeTy[isOfPlCt/@href = $PlCts], 
    $PlSpTy in /root/PlSpTys/PlSpTy[isOfPlGeTy/@href = $PlGeTy/@id], 
    $Cont in /root/Conts/Cont[@id=$PlSpTy/isOfCont/@href] 
return <done>{ $PlGeTy, $PlSpTy, $Cont }</done> 

Это link из последних данных XML для тестирования.

Информационный запрос:

Compiling: 
- applying text index for "AIR" 
- applying attribute index for $PlCts_0 
- applying attribute index for $PlGeTy_1/@id 
- applying attribute index for $PlSpTy_2/isOfCont/@href 
- inlining $PlCts_0 
Query: 
let $PlCts := /root/PlCts/PlCt[environment = 'AIR']/@id for $PlGeTy in /root/PlGeTys/PlGeTy[isOfPlCt/@href = $PlCts], $PlSpTy in /root/PlSpTys/PlSpTy[isOfPlGeTy/@href = $PlGeTy/@id], $Cont in /root/Conts/Cont[@id=$PlSpTy/isOfCont/@href] return <done>{ $PlGeTy, $PlSpTy, $Cont }</done> 
Optimized Query: 
for $PlGeTy_1 in db:attribute("Output7", db:text("Output7", "AIR")/parent::*:environment/parent::*:PlCt/@*:id)/self::*:href/parent::*:isOfPlCt/parent::*:PlGeTy for $PlSpTy_2 in db:attribute("Output7", $PlGeTy_1/@id)/self::*:href/parent::*:isOfPlGeTy/parent::*:PlSpTy for $Cont_3 in db:attribute("Output7", $PlSpTy_2/isOfCont/@href)/self::*:id/parent::*:Cont return element done { (($PlGeTy_1, $PlSpTy_2, $Cont_3)) } 
Result: 
- Hit(s): 3642 Items 
- Updated: 0 Items 
- Printed: 1159 KB 
- Read Locking: local [Output7] 
- Write Locking: none 
Timing: 
- Parsing: 0.39 ms 
- Compiling: 0.68 ms 
- Evaluating: 585.29 ms 
- Printing: 14.36 ms 
- Total Time: 600.72 ms 
Query plan: 
<QueryPlan compiled="true"> 
    <GFLWOR> 
    <For> 
     <Var name="$PlGeTy" id="1"/> 
     <CachedPath> 
     <ValueAccess data="Output7" type="ATTRIBUTE"> 
      <CachedPath> 
      <ValueAccess data="Output7" type="TEXT" name="*:environment"> 
       <Str value="AIR" type="xs:string"/> 
      </ValueAccess> 
      <IterStep axis="parent" test="*:PlCt"/> 
      <IterStep axis="attribute" test="*:id"/> 
      </CachedPath> 
     </ValueAccess> 
     <IterStep axis="self" test="*:href"/> 
     <IterStep axis="parent" test="*:isOfPlCt"/> 
     <IterStep axis="parent" test="*:PlGeTy"/> 
     </CachedPath> 
    </For> 
    <For> 
     <Var name="$PlSpTy" id="2"/> 
     <CachedPath> 
     <ValueAccess data="Output7" type="ATTRIBUTE"> 
      <IterPath> 
      <VarRef> 
       <Var name="$PlGeTy" id="1"/> 
      </VarRef> 
      <IterStep axis="attribute" test="id"/> 
      </IterPath> 
     </ValueAccess> 
     <IterStep axis="self" test="*:href"/> 
     <IterStep axis="parent" test="*:isOfPlGeTy"/> 
     <IterStep axis="parent" test="*:PlSpTy"/> 
     </CachedPath> 
    </For> 
    <For> 
     <Var name="$Cont" id="3"/> 
     <CachedPath> 
     <ValueAccess data="Output7" type="ATTRIBUTE"> 
      <IterPath> 
      <VarRef> 
       <Var name="$PlSpTy" id="2"/> 
      </VarRef> 
      <IterStep axis="child" test="isOfCont"/> 
      <IterStep axis="attribute" test="href"/> 
      </IterPath> 
     </ValueAccess> 
     <IterStep axis="self" test="*:id"/> 
     <IterStep axis="parent" test="*:Cont"/> 
     </CachedPath> 
    </For> 
    <CElem> 
     <QNm value="done" type="xs:QName"/> 
     <List> 
     <VarRef> 
      <Var name="$PlGeTy" id="1"/> 
     </VarRef> 
     <VarRef> 
      <Var name="$PlSpTy" id="2"/> 
     </VarRef> 
     <VarRef> 
      <Var name="$Cont" id="3"/> 
     </VarRef> 
     </List> 
    </CElem> 
    </GFLWOR> 
</QueryPlan> 

ответ

1

В тех, для петель, результаты двух «больших» XPath выражений уже кэшируются оптимизатором. Кроме того, вы фактически сравниваете атрибуты href/id дважды.

Очистка запроса, устраняющего это двойное усилие, сокращает время выполнения на 90%.

let $PlCts := /root/PlCts/PlCt[environment = 'AIR']/@id 
for $PlGeTy in /root/PlGeTys/PlGeTy[isOfPlCt/@href = $PlCts], 
    $PlSpTy in /root/PlSpTys/PlSpTy[isOfPlGeTy/@href = $PlGeTy/@id] 
return <done>{ $PlGeTy, $PlSpTy }</done> 
+0

В свою очередь, мне также нужно будет получить данные из PlGeTy. Возможно ли это с вашим решением? – user1587140

+0

Нет, вам нужно будет искать его снова (ну, у вас уже есть идентификатор, это может быть все еще быстрее, потому что атрибут будет восстановлен с использованием индекса атрибута, что довольно быстро). Вам также нужна информация из '$ PlSpTys'? Если нет, вы можете перебрать это вместо этого. Пожалуйста, укажите такие требования в вопросе, поскольку он ограничивает соответствующие ответы. –

+0

Я обновил часть «возврат». Извините за недопонимание. @JensErat – user1587140