RSS、Atom、mashup、高級搜索要求和其他成長正使得原生 XML 數據庫成為搜索使用程序和服務的一個首要 組成部分。XML 數據庫類型的優勢在於擅長高效地在大量半結構化(semi-structured)的數據中實行搜索。在本文中,您將發覺一些用於最大化運用 XQuery 和 XML 數據庫的使用程序的功能的通常准繩。
XQuery 和原生 XML 數據庫
在某些狀況下,在原生 XML 數據庫零碎中運用 XQuery(一種用於查詢 XML 數據集合的函數型言語)能夠特別有用。與原則 聯絡 數據庫相比,原生 XML 數據庫在服務於首要是只讀的龐雜查詢時可以提供更快的呼應工夫和開發工夫。XQuery 是當前最基本、最強悍的數據轉換零碎,它圓滿地內置在查詢言語中。借助 XQuery,可以 完成更快的開發工夫,由於無需設計一個單獨的全文本索引零碎,或者為用戶組裝大量數據。
以減慢插入和更新速度為代價,原生 XML 數據庫可以提供無與倫比的開箱即用呼應工夫,由於它們保持數據基本上非規格化(denormalized),提供默許索引,並能極好地使用可用 RAM。但是,在處理超大型數據集時,您還可以 議決遵照以下通常准繩進一步改良 原生 XML 數據庫的查詢呼應工夫。
1、防止規格化
2、采用獨一的元素稱號
3、預先 計算值
4、議決查詢轉換數據
5、分析 XQuery 代碼
6、保存優化列表
這些准繩是通用的,適用於當今可用的許多原生 XML 數據庫,包含 IBM DB2 Exp ress-C、Mark Logic Server、eXist、甚至 Oracle Berkeley DB XML(參見 參考材料 中的鏈接)。接上去,我們 將細致討論這些優化准繩。
防止規格化
設計原生 XML 數據庫方式 時,最首要 的事情是防止運用設計聯絡 數據庫時采用的要領來規格化數據。
原生 XML 數據庫的數據規格化流程觸及到設計多個 XML 文檔類型,這些文檔類型互相鏈接的方式 與聯絡 模型表互相鏈接的方式 相似。但是,在多數狀況下,須要盡能夠少(假如有的話)地規格化原生 XML 數據庫的數據。將本來應該駐留在幾十個聯絡 模型表中的數據存儲到一個 XML 文檔類型中的做法是非常多見的。
現今的大多數 XQuery 完成執行連結(join)操作的效率很低,即便是一個只觸及幾千條記載的基本查詢都須要耗費大量的、令人難以接受的處理工夫。這就使得上面這條決定能無法 應該規格化數據的原則 很明白:永遠不要規格化數據,以免受支撐的查詢須要執行連結操作來挑選記載。
受支撐的查詢是這樣一種查詢,即您可以 合理地預期用戶如何對待您的數據。比方,假如構建一個用於銷售錄像帶的使用程序,您能夠預期用戶會查詢標題中包含某個重要字並且由某個導演執導的一切視頻。因而,您一定期盼表示 視頻的 XML 文檔包含視頻標題和導演姓名。另一方面,對於這個特定的使用程序,您也許不期盼支撐用戶查詢標題中包含某個重要字並且由紐約出生的某位導演執導的一切視頻。換句話說,對於這個視頻使用程序示例,假如您擁有導演的細致信息(不只僅是導演姓名),可以 思慮將這些信息保存在一個單獨的 XML 文檔中。
運用以下兩個互相鏈接的 XML 文檔類型來描畫數據庫:video-rec 和 director-rec,前者帶有關 於視頻的信息,其中包含一個 director-rec 標識符;後者帶有關 於導演的信息。要查詢標題中包含某個重要字且導演出 生於紐約的記載,必須執行連結操作以挑選記載。如前所述,也可以 不支撐這種類 型的查詢,由於這是一種更側重於數據發掘的查詢,而不是大多數閱讀在線視頻商店的用戶通常執行的查詢類型。但是,除非您有細致 原由須要將關於導演的細致信息移動 到一個單獨的文檔類型中,否則應該將這些信息保存在 video-rec 文檔中。
雖然在原生 XML 數據庫中執行連結操作來挑選記載總是低效的,但是在轉換搜索結果中的數據時從多個 XML 文檔提取數據通常是可取的。我此前描畫 的視頻商店可以悄悄松松高效地呈現包含導演出 生地的結果,雖然獲取這個地址須要從原始搜索結果之外的文檔提取數據。以這種要領組裝結果,所需的操作僅限於使用程序曾經挑選和計劃顯示的多數幾條記載,與常規的搜索查詢中連結多個文檔類型所需的資源相比,這種要領的計算和內存需求可以 忽略不計。
采用獨一的元素稱號
獨一元素 總是指向一個 XML 文檔中的同一元素。非獨一元素 可以 出如今 XML 文檔中的隨意位置 ,必須前置一個途徑才有意義。比方,假如一個 XML 文檔包含 10 個類型完全不一樣的節點,每個節點都包含一個日期元素作為其子節點,那麼日期元素就是非獨一元素稱號。采用非獨一元素稱號會影響您評價或分析一些用於定位數據的 XQuery 或 xp ath 替代要領。比方,非獨一元素可以阻止您正確評價執行較少索引查詢的代碼。此外,非獨一元素還會障礙正在興起 的對面搜索結果(faceted search result)的支撐。
以下小節提供各種優化的例子,您可以 議決修正 相似於 清單 1 中的文檔的設計以便它運用獨一的元素稱號,來支撐這些優化。
清單 1. 帶有非獨一元素稱號的基本文檔
#+BEGIN_SRC nXML-mode
<class-info>
<school>Lusher Elementary School</school>
<grade>10</grade>
<teachers>
<teacher>
<name>
<first>Carol</first>
<last>Osborne</last>
</name>
</teacher>
<teacher>
<name>
<first>Dan</first>
<last>Silver</last>
</name>
</teacher>
</teachers>
<students>
<student>
<name>
<first>BarrIE</first>
<last>Stoff</last>
</name>
</student>
<student>
<name>
<first>Andrew</first>
<last>Silver</last>
</name>
</student>
<student>
<name>
<first>Larry</first>
<last>Cracchiolo</last>
</name>
</student>
<student>
<name>
<first>Richard</first>
<last>Hughes</last>
</name>
</student>
<student>
<name>
<first>Bruce</first>
<last>Silver</last>
</name>
</student>
.
.
.
</students>
</class-info>
#+END_SRC執行較少的索引查詢
要查詢姓 Silver 的先生的名,應該運用相似於 清單 2 中的 xp ath 表達式。
清單 2. 查詢姓 Silver 的先生的 xp ath 表達式
: /class-info/students/student/name[last = "Silver"]/first
假如將數據限定為 清單 1 中單個文檔中的可見數據,那麼計算 清單 2 中的 xp ath 表達式總是正確地前往 清單 3 中的結果。
清單 3. xp ath 結果
<first>Andrew</first>
<first>Bruce</first>
假如數據沒有被索引,那麼 清單 2 總是獲得 結果的最快要領。這個表達式限定了數據庫找到有關結果所必須搜索的分支的數目。
但是,假如數據曾經索引,並且根據您運用的特定數據庫完成,假設您有一個特別大的數據集,那麼相似於 清單 4 中的表達式能夠計算速度更快。
清單 4. 數據已索引時運用的 xp ath 表達式
: //name[last = "Silver"]/first
功能能夠會改良的原由是,零碎只需檢驗索引中較少的元素。但是,鑒於 清單 1 中文檔的設計(運用非獨一元素稱號),清單 4 中的 xp ath 表達式將前往不正確的結果:包含一個教師的名字 Dan。這種設計阻止您編寫使用較少索引的查詢。更好的設計是運用獨一元素稱號交換 清單 1 中的非獨一元素稱號,如 清單 5 所示。
清單 5. 運用獨一元素稱號交換清單 1 中的非獨一元素稱號
//teacher/name => //teacher/teacher-name
//teacher/name/first => //teacher/teacher-name/teacher-first
//teacher/name/last => //teach/teacher-name/teacher-last
//student/name => //student/student-name
//student/name/first => //student/student-name/student-first
//student/name/last => //student/student-name/student-last
面搜索的目的是顯示一些鏈接,准許用戶沿各種軸高速直觀地減少搜索的范圍。在一個支撐面搜索結果的使用程序中,一個列出數據庫中一切教師的查詢能夠在用戶界面中前往相似於 清單 6 中的信息。
清單 6. 面搜索
Tabor, Gavin
Nance, Jamey
Haas, Carlene
DavIEs, Yesenia
Singer, Lupe
Narrow your search:
School
Lusher Elementary School (35)
Academy of the Sacred Heart (34)
Isidore Newman School (32)
Audubon Charter School (28)
Benjamin Franklin Elementary Math-ScIEnce Magnet (25)
Grades
9 (5)
10 (6)
11 (6)
12 (6)
清單 6 提供了兩個面:School 和 Grades。每個面包含 4 到 5 個值,這些值鏈接到一個搜索,該搜索用於減少近來的搜索的范圍。每個面值旁邊有一個數字(位於圓括號中),表示 單擊這個鏈接將會找到的教師總數。面搜索結果通常只顯示每個面的多個能夠值。假如一個面的確切值的數目很少,比如說 Grades 面,那麼使用程序通常會顯示一切面,並按照各個面的首要 程度排序。但是,假如一個面包含許多能夠值,那麼使用程序通常只顯示將前往最多結果的那些值,並根據結果數目按降序陳列。
一些原生 XML 數據庫正在包含對面搜索的支撐,但是它們須要特殊的索引才能提供最好功能。隨著數據庫中的記載數目的添加和一個面的能夠值的數目添加,獲取一個面的顯示值的典型 XQuery 算法很快成為一個瓶頸。對於一個擁有多個包含數千個值的面的大型數據庫來說,這樣的算法是行不通的。要發揮面搜索的威力,原生 XML 引擎須要可以從一個元素在數據庫中具有的值構建詞典。這些詞典可以 從特殊的索引完成,而索引又須要獨一元素稱號。
假如您擁有一個絕對較小的不支撐面搜索的原生 XML 數據庫,並且須要本身 編寫代碼來支撐這種功能,那麼您將明白,獨一元素稱號對您的代碼有多麼首要 ,就跟它們對更高級的數據庫中當前存在的面搜索支撐代碼一樣首要 。
預先 計算值
將冗余數據添加到 XML 文檔的想法對於干練的聯絡 數據庫維護員來說是不可思議的。但是,當您的首要重視點是功能時(比方,當您必須為查詢幾千萬條記載的查詢前往面搜索結果時),基於 XML 文檔中的數據預先 計算一些值並將結果添加到 XML 文檔中有助於極大地改良 呼應工夫。原生 XML 數據庫都是以犧牲存儲空間並容忍冗余為代價來換取功能的。
假定您擁有一些圖像元數據 XML 文檔。每個 XML 文檔都有一個或多個以下元素:camera、device 和 scanner,這些元素都包含關於建立圖像的裝備 的信息。device 元素表示 一個龐雜節點,它包含一個帶有裝備 稱號的元素和其他多個帶有額外信息的元素。在本例中,一切這些 device 元素都須要在使用程序的其他部分運用,因而無法丟棄。這個使用程序完成面搜索並調用一個名為 scanning device 的面,該面顯示建立圖像的裝備 的稱號。
相似地,這些圖像元數據文檔還具有高度和寬度元素,但是使用程序調用一個名為 size 的面,這個面可以 從 height 和 width 元素悄悄松松得到。
清單 7 是一個示例。
清單 7. 第一個圖像元數據文檔示例
<image>
<id>123456789</id>
<date>2009-11-16T03:14:42</date>
<description>Eiffel Tower</description>
<device>
<device-name>Scanmelter 2000</device-name>
<device-resolution>300dpi</device-resolution>
<device-manufacturer>Scanners Inc.</device-manufacturer>
<service-tag>ASDFQWER</service-tag>
</device>
<width>1200</width>
<height>1024</height>
</image>
清單 8. 第二個圖像元數據文檔示例
<image>
<id>123456788</id>
<date>2009-11-16T03:14:42</date>
<description>Empire State Building</description>
<scanner>Pixel Maker LS</scanner>
<width>800</width>
<height>600</height>
</image>
如今假設一個數據庫具有足夠的記載,查詢拍攝於 2009-11-16 的圖像將前往 5,000 個圖像。使用程序顯示了其中 30 個圖像。搜索結果視圖顯示各個面,包含 scanning device 和 size,每個面提供一個短的值列表。scanning device 面值包含 Scanmelter 2000 (1202) 和 Pixel Maker LS (207)。size 面值包含 1200x1024 (2302) 和 800x600 (113)。
想想您要編寫什麼代碼才能滿足上述要求。這個代碼編寫起來特別基本 ,但是伸縮性不好,由於它必須完成大量的工作來計算滿足每個面值表示 的查詢的記載數。面值能夠有數 百個,代碼須要計算每個面值的結果數目,以便確定為該面列出哪 5 個面值。隨著數據庫中的記載數目、使用程序顯示的面數目以及每個面能夠的面值數目的添加,狀況會高速 變得更糟。假如使用程序須要顯示 50 個面並處理數百萬條記載,那麼您別無挑選,只好預先 計算面值並將其包含在記載中。
清單 7 和 清單 8 中的 XML 文檔都將包含兩個新元素:scanner-name 和 size。這個基本的修正 將准許這個完成具有更好的伸縮性。
議決查詢轉換數據
XQuery 的最大優勢在於可以嚴厲按照調用者的需求提供數據,但這個優勢能夠使用得最不好。通常,結構師傾向於將原生 XML 數據庫當作一個後端 XML Web 服務,它前往前端應該根據須要實行轉換和呈現的 XML 文檔。
曾經運用 XQuery 從原生 XML 數據庫檢索數據的公司,很基本 說出前往 XML 格式的數據、然後運用(比方)XSLT 在前端轉換數據的一切原由。以下是一些最多見的原由:
我們 計劃建立其他產品,它們將相似的數據用於其他目的 。
我們 有前端員工曾經明白如何 運用 XSLT、Perl、PHP、Javascript 和 Java 言語。
我們 想要一個面向服務的結構(Service-OrIEnted Architecture)。
我們 都不明白 XQuery,因而我們 想盡量限定它的運用。
們有一個現成的數據管道。
XQuery 看起來很龐雜。
XQuery 無法做什麼什麼。
這裡沒有足夠的篇幅來逐一 駁斥這些理由,但請記得以下幾點:
預備呈現給閱讀器的數據通常比數據庫存儲的原始數據小得多。
無論根據何種原則 ,XQuery 都比 XSLT 更基本、更強悍、更精簡。
在輸入時轉換數據比稍後運用 XSLT(或其他任何工具)轉換數據要快得多。
您可以 編寫 XQuery 以便客戶端可以懇求各種格式的數據。
假如轉換數據的代碼接近定位數據的代碼且二者運用相似的言語編寫,那麼使用程序的常規龐雜性將極大地降低。
上述第一點 — 比較要呈現的數據的大小和原始的、未轉換的數據的大小 — 須要額外說一下。留心大型 XML 記載。盡量防止發送大型記載到前端並在那裡轉換。將盡能夠小的數據塊放到網絡上通常可以改良 使用程序的呼應性和伸縮性。應該時常這樣做:在數據從數據庫出來的流程直達換數據時,將較小的數據塊放到網絡上。
對於那些未能使用 XQuery 的一切 威力的公司,真實的原由是害怕未知事物。這一點完全可以 理會 ,但假如您曾經在運用原生 XML 數據庫了,那麼發揮它的一切 才能最後只會使事情變得更好。
分析 XQuery 代碼
通常來說,分析代碼意味著確定計算機在代碼的每一部分所花費的工夫。目的 是辨認代碼中最基本 獲得優化成效的部分。這些部分並不必須是運轉得最慢的;有時,一段曾經非常高效的代碼能夠將是您最想重視的部分。比方,一段運轉工夫為 10 秒的代碼很基本 優化為在 1 秒內運轉。但是,假如那段代碼每天只運轉一次,那麼您最好將精力放在改良每天運轉 1,000,000 次的函數速度上,雖然進步的幅度能夠很巨大。
大多數原生 XML 數據庫擁有一些工具來對代碼實行基准測試或分析。運用這些工具吧。有時,這些工具不會以您想要的方式 測量某些特定代碼段的功能。假如遇到這種狀況,應該毫不猶疑地建立本身 的代碼來對進程實行基准測試。在本身 的 XQuery 模塊中插入代碼來標記和測量工夫不會產生任何疑問,尤其是您可以 在消費中禁用基准測試代碼時。
此外,由於 XQuery 是一種函數型編程言語,所以每個函數都是獨立的。在很大程度上,一個 XQuery 函數的前往序列只取決於調用該函數時運用的參數。因而,開發單元測試和功能測試來訪問 XQuery 函數比運用原則 流程型編程言語(如 Java、Python、Perl、C 和 PHP)來開發函數測試更基本 。可以 用外部進程(比如一個高速腳本)悄悄松松地測量 XQuery 代碼中函數的執行工夫。比方,一個精巧的 EMacs 腳本准許您運轉您正在編輯的 XQuery 代碼並測量代碼的執行工夫,您須要做的只是突出顯示相應代碼並敲擊一個組合鍵。這個腳天分 夠將代碼發送到服務器,讓服務器評價代碼,然後將結果前往到一個帶有執行工夫戳的新緩沖區。
保存優化列表
您應該保存一個您的平台適用的潛在優化列表,並在每次須要改良 使用程序的功能時閱讀整個列表。除了本文曾經推選 過的優化外,我還將以下各項保存在我的列表中。
盡能夠預先 編譯代碼
一些原生 XML 數據庫具有預先 編譯或分析 XQuery 代碼的才能。對於在服務器上頻繁運轉的代碼,假如您可以確保服務器在每次遇到該代碼時都不必分析或編譯它,那麼會看到清楚的功能改良 。
針對索引編寫代碼
在許多狀況下,原生 XML 數據庫都可以計算 XQuery 或 xp ath 表達式並從索引直接處理查詢,無需檢索任何文檔。假如能夠,您應該盡量編寫這種類 型的查詢。尋覓一個數據庫選項或搜索函數選項,以准許您的查詢直接從索引檢索結果並防止任何種類 的結果有效性過濾。
從索引檢索結果並且不實行過濾也有其缺陷。假如您在搜索的節點不是頂級節點(或片段根),那麼您必須留心 。做好理會 結果的預備,由於結果中能夠包含經歷過濾的搜索結果中不包含的節點。
思慮 XQuery 擴展
大多數原生 XML 數據庫提供用於高速運轉的 XQuery 擴展。當您偏離嚴厲的 XQuery 時,您的使用程序將愈加依托 於某個特定的產品,但在實際 和消費中,當處理大量數據時,您一定想思慮功能擴展的優勢。笨重是有代價的。
理會 森林、樹木和合並
一些原生 XML 數據庫將它們的數據以二進制文件格式保存在森林(目錄)中,森林又包含樹木(文件)。新記載通常進入新樹木中。零碎(或維護員)定期合並樹木以進步功能 — 森林中的樹木越少,查詢呼應工夫就越好。但您不會期盼森林變得太大。優化零碎時,應該在開端(或配置零碎以開端)合並之前檢驗森林的最優大小和樹木的最優數目。
因而,數據加載將觸發合並。合並能夠會降低接近極限吞吐量的零碎的功能。假如能夠,應該在零碎負載最低時安排數據加載和合並。與數據合並相比,數據加載對功能的影響要小得多。假如數據加載要運轉很長一段工夫,那麼思慮在加載峰值時期禁用數據合並。
結束語
原生 XML 數據庫當前驅動的站點支撐對包含數千萬條記載的數據庫實行龐雜的搜索。對於某些使用程序而言,在適當的狀況下,這些數據庫可以讓運用它們的公司絕對於較慢的采用者,擁有更大的競爭優勢。但正像其他數據庫技能一樣,原生 XML 數據庫將讓那些知曉如何 優化零碎以進步效率和呼應性的公司獲得 最大的收益。
後注:
常用縮寫詞:
RAM:隨機存取存儲器
RSS:真實基本聚合
XML:可擴展標記言語
XSLT:可擴展樣式 表言語轉換