2015-12-03 32 views
0

我有以下數據:如何在XQuery中進行高效的外部或左連接?

<!-- subjects.xml --> 
<Subjects> 
    <Subject> 
     <Id>1</Id> 
     <Name>Maths</Name> 
    </Subject> 
    <Subject> 
     <Id>2</Id> 
     <Name>Science</Name> 
    </Subject> 
    <Subject> 
     <Id>2</Id> 
     <Name>Advanced Science</Name> 
    </Subject> 
    <Subject> 
     <Id>3</Id> 
     <Name>History</Name> 
    </Subject> 
</Subjects> 

將被加入到:

<!-- courses.xml--> 
<Courses> 
    <Course> 
     <SubjectId>1</SubjectId> 
     <Name>Algebra I</Name> 
    </Course> 
    <Course> 
     <SubjectId>1</SubjectId> 
     <Name>Algebra II</Name> 
    </Course> 
    <Course> 
     <SubjectId>1</SubjectId> 
     <Name>Percentages</Name> 
    </Course> 
    <Course> 
     <SubjectId>2</SubjectId> 
     <Name>Physics</Name> 
    </Course> 
    <Course> 
     <SubjectId>2</SubjectId> 
     <Name>Biology</Name> 
    </Course> 
</Courses> 

我希望做一個左連接上的第一個表到第二個表,以便得到以下輸出:

<Results> 
    <Result> 
     <Table1> 
      <Subject> 
       <Id>1</Id> 
       <Name>Maths</Name> 
      </Subject> 
     </Table1> 
     <Table2> 
      <Course> 
       <SubjectId>1</SubjectId> 
       <Name>Algebra I</Name> 
      </Course> 
      <Course> 
       <SubjectId>1</SubjectId> 
       <Name>Algebra II</Name> 
      </Course> 
      <Course> 
       <SubjectId>1</SubjectId> 
       <Name>Percentages</Name> 
      </Course> 
     </Table2> 
    </Result> 
    <Result> 
     <Table1> 
      <!-- Notice there are 2 subjects here, as they both have the same ID--> 
      <Subject> 
       <Id>2</Id> 
       <Name>Science</Name> 
      </Subject> 
      <Subject> 
       <Id>2</Id> 
       <Name>Advanced Science</Name> 
      </Subject> 
     </Table1> 
     <Table2> 
      <Course> 
       <SubjectId>2</SubjectId> 
       <Name>Physics</Name> 
      </Course> 
      <Course> 
       <SubjectId>2</SubjectId> 
       <Name>Biology</Name> 
      </Course> 
     </Table2> 
    </Result> 
    <Result> 
     <Table1> 
      <Subject> 
       <Id>3</Id> 
       <Name>History</Name> 
      </Subject> 
     </Table1> 
     <Table2> 
      <!-- Notice this section is empty --> 
     </Table2> 
    </Result> 
</Results> 

我有以下的代碼來做到這一點:

<Results> 
    { 
     (: For each element in courses, where it's 'SubjectId' exists in "subjects.xml":) 
     for $e2 in doc("courses.xml")/Courses/Course 
     let $foriegnId := $e2/SubjectId 
     group by $foriegnId 
     let $e1 := doc("subjects.xml")/Subjects/Subject[Id = $foriegnId] 
     where $e1 

     return 
      <Result> 
       <Table1> 
        {$e1} 
       </Table1> 
       <Table2> 
        {$e2} 
       </Table2> 
      </Result> 
    } 

    { 
    (: PART2 :) 
    (:Show the remaining elements in courses that have not yet been outputted:) 
     for $e1 in doc('subjects.xml')/Subjects/Subject 
     let $idVal := $e1/Id 
     group by $idVal 
     where not(doc('courses.xml')/Courses/Course/SubjectId = $idVal) 
     return 
      <Result> 
       <Table1> 
        {$e1} 
       </Table1> 
       <Table2/> 
      </Result> 
    } 
</Results> 

請注意代碼工作正常,並完成這項工作。但是,我發現在執行大量輸入代碼時(750個主題,每個主題有120個課程,100個主題沒有任何課程,100個主題沒有任何主題),劇本運行速度極慢!

怎樣才能讓我的腳本更快?有沒有更好的方法來做到這一點?時間複雜度是多少?

更新2

原來我已經嚴重誤判的問題。這個問題實際上與代碼的第2部分很少有關,而是代碼的第1部分。

我所做的是:

for $e2 in doc("courses.xml")/Courses/Course 
let $foriegnId := $e2/SubjectId 
let $e1 := doc("subjects.xml")/Subjects/Subject[Id = $foriegnId] 
group by $foriegnId 

的時候我應該做的是:

for $e2 in doc("courses.xml")/Courses/Course 
let $foriegnId := $e2/SubjectId 
group by $foriegnId 
let $e1 := doc("subjects.xml")/Subjects/Subject[Id = $foriegnId] 

這降低了代碼的時間從30,000ms左右4,000ms。

進一步的性能改進值得歡迎。

+0

你可以給你的測量?你在使用撒克遜-HE還是撒克遜-EE? –

+0

對於大型數據集的基準測試問題,僅提供小型提取(對於問題本身而言是很好的,但應該提供您針對自己進行基準測試的數據集)幾乎沒有幫助。另外,給出確切的軟件版本也很有幫助。 –

+0

撒克遜9.7是evrsion我正在使用 –

回答

1

根據查詢優化的方式,ID列表可能會一次又一次地放在一起,每個主題一次。提前一次獲取列表,然後對此進行驗證。

let $subjectIds := doc('courses.xml')/Courses/Course/SubjectId 
    for $e1 in doc('subjects.xml')/Subjects/Subject 
    let $idVal := $e1/Id 
    group by $idVal 
    where not($subjectIds = $idVal) 
    return 
     <Result> 
      <Table1> 
       {$e1} 
      </Table1> 
      <Table2/> 
     </Result> 

進一步優化可能是部分冗餘主題ID列表修剪他們的不同值的前一個序列:

let $subjectIds := distinct-values(doc('courses.xml')/Courses/Course/SubjectId) 
+0

這似乎沒有太多的腳本執行時間的影響。也就是說,我確實加入了它,因爲它可能成爲其他XQuery引擎的問題。 –