xml與數據庫

XML與數據庫

copyright 1999-2005 by Ronald Bourret
原作最後更新: 2005年9月
原文: www.rpbourret.com
翻譯: onestab 2006.11.20(修訂) 

1.0 簡介 (Introduction)

本文概述瞭如何使用XML和數據庫,描述了以數據爲中心和以文檔文中心的文檔之間的差異如何影響其在數據庫中的應用,使用XML和關係型數據庫的常見方法,以及什麼是原生XML數據庫和何時使用它。

注: 儘管本文討論的資料(幾乎)是最新的,但使用以數據爲中心和以文檔文中心來劃分XML與數據庫有些過時。在1999年本文的初稿中,這樣做有利於引入原生XML數據庫的概念-當時尚未得到廣泛的認可,從某種程度上來說不太現實,因爲許多XML文檔既非數據型的亦非文檔性的,而是介於兩者之間,所以儘管這種劃分便於入門,最好還是要理解支持XML的數據庫與原生XML數據庫之間的差別,並根據需要選擇合適的數據庫。有關支持XML的數據庫與原生XML數據庫的最新信息,參見DB2的XML信息集成。

2.0 XML是數據庫嗎?(Is XML a Database?)

在開始討論XML和數據庫之前,我們先回答許多人都遇到過的問題:“XML是數據庫嗎?”

從數據庫本質上來看,XML文件就是數據庫,它是數據的集合。在許多方面看起來它和其他文件沒什麼區別 -- 無論如何,每個文件都含有某種類型的數據。作爲一種“數據庫”格式,XML有一些優勢:例如,它是自描述的(所用的標記描述了數據的結構和類型,儘管缺乏語義),可交換的(portable)(Unicode),能夠以樹型或圖形結構描述數據。同樣它也有缺點,例如,它顯得有些繁瑣,由於要對它進行解析和文本轉換,所以數據訪問速度較慢。

一個更有用的問題就是在較爲寬鬆的意義上,XML及其周邊技術是否可以算作“數據庫” -- 數據庫管理系統(DBMS)。答案是“在某種程度上是(sort of)”。好的一面是,XML提供了許多數據庫所具備的東西:存儲(XML文檔), 模式(DTD, XML schema,RElAX NG 等等), 查詢語言(XQuery, XPath, XQL, XML-QL, QUILT等等),編程接口(SAX, DOM,JDOM)等等。不好的一面在於,它缺少一些作爲實用的數據庫所應具備的特性:高效的存儲,索引,安全,事務和數據一致性,多用戶訪問,觸發器,在查詢多個文件等等。

因此,儘管在數據量小、用戶少和性能要求不太高的環境下,可以將XML文檔用作數據庫,但是卻不適用於用戶量大、數據完整性以及性能要求高的情形。

XML適合於用作所謂“數據庫”的一個好例子就是 .ini文件 -- 它包含應用程序的配置信息。與其寫一個處理以逗號分隔(comma-delimited)的文件的解析器,開發一種小型的XML語言並寫一個解釋它的 SAX程序要容易的多。此外,XML允許使用嵌套的實體,而逗號分隔的文件(comma-delimited files)很難做到這點。然而,說它就是數據庫還很勉強,因爲它是線性讀寫的,而且僅用在程序開始和結束時。

比較適合於XML數據庫的一些複雜的數據集就是個人通訊錄(名字,電話號碼,地址等),或用於描述瀏覽器書籤以及用Napster偷來的MP3。然而,由於dBase和Access之類的數據庫物美價廉,即使在這種情況下似乎也沒有多少理由把XML文件作爲數據庫使用。XML的唯一真正好處就是數據的可交換性(portable),由於有越來越多的工具可以用來對數據庫進行XML序列化(serializing),這一點好處似乎也要打些折扣。

3.0 爲什麼要用數據庫?(Why Use a Database?)

當你開始考慮XML和數據庫的時候,可能首先會問這個問題:爲什麼你會先想到使用數據庫?你是否有可用的歷史數據?是否想找個地方存儲Web頁面? 是否在電子商務中使用數據庫,而XML在其中作爲數據傳輸載體? 對這些問題的回答將會極大地影響你對數據庫和中間件(如果有的話)的選擇,以及如何使用所選的數據庫。

例如,你有個電子商務的應用,將XML用作數據交換。那麼你的數據最好有個非常規則的結構並且可供非XML程序使用。還有,XML文檔所用的某些東西如實體和編碼對你來說並不重要 --總之,你感興趣的是數據,而不是它在XML內如何存儲。在這種情況下,你大概需要一個關係型數據庫以及在XML和數據庫之間轉換數據的軟件。如果你的應用程序是面向對象的,你甚至還需要一個在數據庫或XML中存取這些對象的系統。

另一方面,假如你要從一些結構鬆散的XML文檔建立一個網站。你不但要管理這個網站,還要提供站點內容搜索。你的文檔看起來結構比較鬆散,其中的實體的使用對你來說可能更重要,因爲它們是文檔結構的重要部分。這種情況下,你也許需要一個原生XML數據庫(native XML database)或內容管理系統(content management system)。這使你可以保持文檔的物理結構,支持文件級的事務處理,以及使用XML Query語言進行查詢。

4.0 數據和文檔 (Data versus Documents)

在選擇數據庫時最重要因素大概就是你想在數據庫存儲的究竟是數據還是文檔。例如,是簡單地把XML當作數據庫和(可能不支持XML)應用程序之間的數據轉換工具,還是用於集成,就像XHTML和DocBook中的那樣?通常這是個偏好,但是卻非常重要,因爲所有以數據爲中心(data-centric)文檔有着許多相同的特性,所有以文檔爲中心(document-centric)也有許多相同的特性。這會影響到XML在數據庫中如何存儲。下面兩部分中我們就來考察這些特性。

(歷史背景:我在xml-dev郵件列表上第一次聽說data-centricdocument-centric這些術語,不知道是誰發明的,但是我在1997的消息中發現有使用document-centric的,從1998年以後這兩個術語都有使用。)

4.1 以數據爲中心的文檔 (Data-Centric Documents)

以數據爲中心的文檔就是將XML用作數據的傳輸載體,只供機器讀取,在此XML通常並不是絕對必要的。也就是說,對於應用程序或數據庫而言,(在某個時間段內)數據是否以XML文檔的形式存儲並不重要。以數據爲中心的文檔的例子有銷售訂單、航班時刻表、科研數據及股市匯率。

以數據爲中心的文檔的特點是結構相當規整,數據粒度精細(fine-grained data)(即最小的獨立數據單位只存在於PCDATA元素或屬性這一級別),很少或沒有混合內容。除非在對文檔進行驗證的時候,同級元素或PCDATA的出現次序一般來說並不重要。

以數據爲中心的文檔中的這類數據可以來自數據庫(此時要輸入給XML)或在數據庫之外(此時要將其存入數據庫)。前者的一個例子就是關係數據庫現存的大量數據;而從測量系統採集並轉化爲XML的科研數據就是後者的例子。

例如,下面的銷售訂單就是以數據爲中心的:

     <SalesOrder SONumber="12345">
      <Customer CustNumber="543">
         <CustName>ABC Industries</CustName>
         <Street>123 Main St.</Street>
         <City>Chicago</City>
         <State>IL</State>
         <PostCode>60609</PostCode>
      </Customer>
      <OrderDate>981215</OrderDate>
      <Item ItemNumber="1">
         <Part PartNumber="123">
            <Description>
               <p><b>Turkey wrench:</b><br />
               Stainless steel, one-piece construction,
               lifetime guarantee.</p>
            </Description>
            <Price>9.95</Price>
         </Part>
         <Quantity>10</Quantity>
      </Item>
      <Item ItemNumber="2">
         <Part PartNumber="456">
            <Description>
               <p><b>Stuffing separator:<b><br />
               Aluminum, one-year guarantee.</p>
            </Description>
            <Price>13.27</Price>
         </Part>
         <Quantity>5</Quantity>
      </Item>
   </SalesOrder>

除了像銷售訂單這種顯而易見的以數據爲中心的文檔之外,許多以文本爲主的(prose- rich)文檔也可以是以數據爲中心的。例如,Amazon.com用來顯示書籍信息的一個頁面。儘管頁面上大部分內容都是文本,這些文本的結構是非常規則的,許多都和其它書籍的描述相同,每個頁面特有的文本並不很多。這樣,就可以從數據庫中取出書籍的相關資料,轉換爲簡單的、以數據爲中心的XML文檔,再用XSL樣式表生成頁面。一般來說,那些用數據庫中的數據填充模板,動態生成HTML文件的網站都可以轉而使用一系列以數據爲中心的XML文檔和XSL樣式表。

例如,下面是個描述航班信息的文檔:

   <FlightInfo>
      <Airline>ABC Airways</Airline> provides <Count>three</Count>
      non-stop flights daily from <Origin>Dallas</Origin> to
      <Destination>Fort Worth</Destination>. Departure times are
      <Departure>09:15</Departure>, <Departure>11:15</Departure>,
      and <Departure>13:15</Departure>. Arrival times are minutes later.
   </FlightInfo>

從下面的XML文件和一個簡單的樣式表中創建這個文檔:

   <Flights>
      <Airline>ABC Airways</Airline>
      <Origin>Dallas</Origin>
      <Destination>Fort Worth</Destination>
      <Flight>
         <Departure>09:15</Departure>
         <Arrival>09:16</Arrival>
      </Flight>
      <Flight>
         <Departure>11:15</Departure>
         <Arrival>11:16</Arrival>
      </Flight>
      <Flight>
         <Departure>13:15</Departure>
         <Arrival>13:16</Arrival>
      </Flight>
   </Flights>

4.2 以文檔爲中心的文檔 (Document-Centric Documents)

以文檔爲中心的文檔通常是供人消費的。例如書籍、email、廣告以及幾乎所有人工寫成的XHTML文件。其特性爲結構不太或根本不規則、數據粒度大(larger grained data)(最小的獨立數據單位可能存在於包含混合內容的元素甚至整個文檔本身),混合內容多。同級元素或PCDATA出現的次序一般來說總是非常重要的。

以文檔爲中心的文檔通常是以XML手工寫成,或從其他格式(如RTF, PDF, SGML)轉換到XML,與以數據爲中心的文檔不同,它們的來源通常不是數據庫。(將數據插入到模板而得到的文檔是以數據爲中心的;更多信息請看4.1節末尾部分)。將各種格式轉換爲XML的軟件信息,請參閱XML軟件相關鏈接

例如,下面這個產品說明是以文檔爲中心的:

   <Product>

   <Intro>
   The <ProductName>Turkey Wrench</ProductName> from <Developer>Full
   Fabrication Labs, Inc.</Developer> is <Summary>like a monkey wrench,
   but not as big.</Summary>
   </Intro>

   <Description>

   <Para>The turkey wrench, which comes in <i>both right- and left-
   handed versions (skyhook optional)</i>, is made of the <b>finest
   stainless steel</b>. The Readi-grip rubberized handle quickly adapts
   to your hands, even in the greasiest situations. Adjustment is
   possible through a variety of custom dials.</Para>
   
   <Para>You can:</Para>
   <List>
   <Item><Link URL="Order.html">Order your own turkey wrench</Link></Item>
   <Item><Link URL="Wrenches.htm">Read more about wrenches</Link></Item>
   <Item><Link URL="Catalog.zip">Download the catalog</Link></Item>
   </List>
   
      <Para>The turkey wrench costs <b>just $19.99</b> and, if you
   order now, comes with a <b>hand-crafted shrimp hammer</b> as a
   bonus gift.</Para>
   
   </Description>
   
   </Product>

4.3 數據、文檔和數據庫(Data, Documents, and Databases)

在現實當中,以數據爲中心和以文檔爲中心的文檔之間的差別不一定很明顯。例如,另一種以數據爲中心的文檔比如發票,可能含有大粒度的、結構不規則的數據比如零件描述;另一種以文檔文中心的文件如用戶手冊,可能包含細粒度的結構規則的數據(通常爲元數據)比如作者和修訂日期。其它例子包括法律和醫學文書,雖然以鬆散的形式寫成但是卻包含離散的數據塊例如日期、名稱和操作程序,出於法規的原因通常要以完整的文件形式存儲。

除此之外,弄清文件的這兩種特點有助於選擇數據庫的類型。一般來說,將數據存儲於傳統的數據庫,例如關係型,面向對象型或層次型數據庫。這可由第三方的中間件完成或由數據庫本身提供內在支持。對於後者,該數據庫被稱作支持XML的(XML-enabled)。文檔可被存儲在原生(native)XML數據庫(專爲存儲XML而設計的數據庫)或內容管理系統(建在原生XML數據庫之上專門用來管理文檔的程序)。

這些原則並不是絕對的。如果對XML特有的功能不很看重,數據,特別是半結構化的數據可以存儲在原生XML數據庫,文檔也可以存儲到傳統數據庫。何況傳統數據庫與原生XML數據庫之間的界限越來越模糊,傳統數據庫增加了原生XML的能力,而原生XML數據庫增加了對文檔存儲在外部(通常爲關係型)數據庫的支持。

本文剩下的部分就有關數據(第5節)和文檔(第6節)的存儲和讀取的策略與問題展開討論。關於最新的XML數據庫產品,請見XML數據庫產品

5.0 數據的存取(Storing and Retrieving Data)

爲了在XML文件和數據庫之間交換數據,必須將XML文件的schema(DTD,XML Schema, RELAX NG等)映射到數據庫的schema。用於數據轉換的軟件位於這種映射的上層。該軟件可以使用XML Query語言(如XPath,XQuery,或其他專用語言)或簡單地按照映射(SELECT * FROM Table的XML對應形式)轉換數據。

對於後者,文檔的結構必須完全符合映射所要求的結構。由於通常不易做到這點,使用這種策略的產品一般要和XSLT一起使用。在數據轉換到數據庫之前,先將文件按照映射所要求的結構進行轉換,然後轉存數據。相應地,數據從數據庫中取出以後,結果文件要被轉換成應用程序所需的結構。

5.1 映射[XML]文件Schema到數據庫Schema (Mapping Document Schemas to Database Schemas)

文件schema到數據庫schema的映射是在元素類型、屬性和文本上進行的。這時幾乎總是忽略物理結構(例如實體、CDATA部分及編碼信息)及某些邏輯結構(如處理指令、註釋以及元素和PCDATA在父元素內出現的順序)。這樣做是自然而然的,因爲數據庫和應用程序只需關心XML文件中的數據。例如,在上述的銷售訂單中,客戶代號是在CDATA部分,還是外部實體中,或直接就是PCDATA並不重要,同樣,客戶代號出現在訂貨日期之前或之後也無關緊要。

這種方法的一個後果是能否保證文件有“往返車票” -- 將文件中的數據存入數據庫後,又從數據庫中的數據重新構建文件,得到的文件往往和原來的文件不同(哪怕從最簡單的角度來講)。這種情形是否可以接受取決於你的要求,在選擇軟件時要考慮到這一點。

將一個XML文件的schema映射到數據庫的schema有兩種方法:基於表格的映射對象-關係映射

5.1.1 基於表格的映射 (Table-Based Mapping)

許多轉換XML到數據庫的中間軟件都採用基於表格的映射。它把XML文件看作一個(或一組)表格,也就是說,XML文件的結構必須是下面這種樣子,如果只是單一表格的話,就不再需要<database>元素和其他<table>元素:

   <database>
      <table>
      <row>
           <column1>...</column1>
            <column2>...</column2>
            ...
         </row>
         <row>
            ...
         </row>
         ...
      </table>
      <table>
         ...
      </table>
      ...
   </database>

根據所用軟件的不同,可以將各字段數據以子元素的形式或以屬性的形式存儲,同樣也可以指定這些元素或屬性的名字。此外,採用基於表格映射方式的軟件還可能允許在文件開始的地方包含表格或各字段的元數據,或者將其作爲各表格或元素的屬性。注意這裏所說的“表格”是泛指的表格。當將數據從數據庫中轉到XML文件時,“表格”可以是任何結果集,反之,“表格”可以是普通的表格或可更新的視圖。

基於表格的映射對存取關係型數據比較適用,比如在兩個關係型數據庫之間轉換數據。其明顯不足就是不適于格式不符的XML文件。

5.1.2 對象-關係映射 (Object-Relational Mapping)

所有支持XML的關係型數據庫和某些中間件都可以使用對象-關係的映射方式。它將XML文件中的數據視爲特定的對象樹的模型。在這個模型中,元素及其類型、元素內容或混合內容(複合元素類型)通常被視爲類。只具有PCDATA內容的元素(簡單元素類型)、屬性以及PCDATA都被當作簡單屬性。然後通過傳統的對象-關係映射技術或 SQL 3的對象視圖將該模型映射到關係型數據庫。也就是說,類被映射到表格,簡單屬性被映射到字段,而值爲對象屬性被映射爲成對的主鍵/外鍵(primary key/foreign key)。

(所謂“對象-關係映射”有些名不副實。因爲對象樹可以被直接映射到面向對象型和層次型數據庫,然而,但是由於大多數使用這種映射方式的主流產品使用的其實是關係型數據庫,所以“對象-關係映射”也就廣爲人知。)

我們在理解這種映射所用的對象模型的時候要知道,這個對象模型不是文件對象模型(DOM)。所有XML文件的DOM都是一樣的,而上述描述文件數據的模型對於每個DTD所定義的XML文件都不一樣,例如,上述銷售訂單的模型是一個由四個類所組成的對象樹--SalesOrder, Customer, Item, 和Part, 如下圖所示:

                    SalesOrder
                   /    |    /
             Customer   Item   Item
                         |      |
                        Part   Part

在由同一個文件產生的DOM中,對象樹的組成是元素、屬性和文本:

                          元素 --- 屬性
                    (SalesOrder) (SONumber)
               ____/   /   /   /_____
              /       /     /        /
          元素      文本     元素     元素
     (Customer) (OrderDate)  (Item)    (Item)
          |                    |         |
         etc.                 etc.      etc.

模型中的對象是否被實例化要取決於所用的軟件。有些軟件允許依據模型產生類,然後可以在程序中使用由這些類所產生的對象。在這些產品中,數據是在XML文件 - 對象 -數據庫之間傳遞的。其他產品是直接在XML文件和數據庫之間進行數據轉換的,對象只是作爲這種過程的可視化幫助工具。生成這些中間對象是否有用完全取決於你的應用程序。

(根據Sun的 Java Architecture for XML Binding,XML文件與對象的綁定通常被稱爲XML數據綁定(XML data binding),有些產品支持XML數據綁定,其中許多還可以在對象和數據庫之間進行數據交換,更多的信息,請看XML數據綁定相關資源 XML Data Binding Resources.)

各種產品對對象-關係映射的具體支持各不相同。例如:

  • 所有產品都支持從複合元素類型到類,以及從簡單元素類型和 屬性(attributes)到[類的]屬性(properties)的映射。
  • 所有(?)產品都允許你指定是否將根元素映射到對象模型或數據庫。如果你想在同一個XML文檔中存儲多個頂級對象時,這個包裝元素(wrapper element)就顯得有用了。例如,如果你想在同一個XML文件中存儲多個銷售 訂單,就必須把它們包裝在一個根元素內。

    當使用基於表格的映射的XML文件有多個表格組成時,這個包裝元素就相當於<database>元素,他的存在只是爲了滿足 XML 文件只能有一個根元素的要求。少數產品允許你就像指定包裝元素那樣,在較低的層次上指定[某些元素是否被映射 -譯註]。

  • 大多數產品允許你說明將[對象的]屬性(properties)映射到XML文件中的屬性(attribute)還是子元素。某些產品還允許 你混合使用屬性和子元素,其他的只允許你使用兩者之一。
  • 大多數產品允許XML文件和數據庫的名字可以不同。少數產品要求必須使用相同的名字。
  • 大多數產品允許你說明子元素在父元素中的出現次序,儘管如此,仍然不可能建立多個內容模型。幸好對於大多數以數據爲中心的文檔而言,所支持的內容模型已經足夠。(當文件需要驗證時,子元素的次序才顯得相當重要。)
  • 某些產品允許你將複合元素類型映射到簡單屬性 (properties)。當某個元素包含混合內容(例如銷售訂單中的< Description>元素)時,這點相當有用。儘管<Description>元素像XHTML一樣包含子元素和文本,但最好還是 將這個description視爲單個屬性,而不是把它分成許多碎塊。
  • 支持混合內容中的PCDATA映射的產品不多。

關於對象-關係型映射的詳細描述,請看第三部分“將DTD映射到 數據庫”。

5.2 查詢語言(Query Languages)

許多產品都是按照它們所建的模型直接進行數據交換。由於XML文件的結構和數據庫的結構一般不同,這些產品一般都使用了或包括了XSLT樣式表。這就允許用戶在數據被交換到數據庫之前(或相反)根據模型規定的格式對文件進行轉換。由於XSLT處理的代價較高,某些產品只提供有限幾種這樣的轉換。

這個問題的長久解決方案就是設計一種可以返回XML[文件]的查詢語言。目前來看(2002年11月),大多數這種語言都依賴於在模板中嵌入 SELECT 語句。到 XQuery 最後定稿時這個局面有望得到改變,正如主流的數據庫產品提供商已經做的那樣。不幸的是,幾乎所有的XML查詢語言(包括 XQuery1.0 和 SQL/XML的最初發布版本)對文件都是隻讀的,所以短期來說,最需要的是能夠插入、更新、刪除數據的手段。(從長遠來看,XQuery 和 SQL/XML 將會增加這種功能。)

5.2.1 基於模板的查詢 (Template-Based Query)

大多數從數據庫讀取XML的查詢語言是基於模板的,這些語言並沒有預先定義XML文件和數據庫之間的映射,相反,是將SELECT語句嵌入到模板中,由數據交換軟件對結果進行處理。例如,下面的模板(並不是真正產品中的)使用包含了SELECT語句和$column-name值的< SelectStmt>元素來決定將結果放在何處。 

<?xml version="1.0"?>
   <FlightInfo>
      <Introduction>The following flights are available:</Introduction>
      <SelectStmt>SELECT Airline, FltNumber,
                  Depart, Arrive FROM Flights</SelectStmt>
         <Flight>
            <Airline>$Airline</Airline>

            <FltNumber>$FltNumber</FltNumber>
            <Depart>$Depart</Depart>
            <Arrive>$Arrive</Arrive>
         </Flight>

      <Conclusion>We hope one of these meets your needs</Conclusion>
   </FlightInfo>

這個模板處理之後的結果可能是:

  <?xml version="1.0"?>
   <FlightInfo>
      <Introduction>The following flights are available:</Introduction>

      <Flights>
         <Flight>
            <Airline>ACME</Airline>
            <FltNumber>123</FltNumber>
            <Depart>Dec 12, 1998 13:43</Depart>

            <Arrive>Dec 13, 1998 01:21</Arrive>
         </Flight>
         ...
      </Flights>
      <Conclusion>We hope one of these meets your needs.</Conclusion>

   </FlightInfo>

基於模板的查詢語言非常靈活。儘管各個產品的功能不盡相同,但有一些共同特性:

  • 可以將返回結果放在輸出文件中的任何地方,包括作爲後續SELECT語句的參數。
  • 可由程序構建 for 循環和 if 語句。
  • 可以定義變量和函數。
  • 可通過HTTP參數實現SELECT語句的參數化(parameterization)。

從關係數據庫中將數據轉換到XML文件時,幾乎一定要用到基於模板的查詢語言。雖然有些產品也將基於模板的查詢語言用於XML文件到關係數據庫的數據轉換,這時所用的並不是完整的模板語言。相反,他們使用的是上面所述的基於表格的映射。

5.2.2 基於SQL的查詢語言 (SQL-Based Query Languages)

基於SQL的查詢語言使用的是經過修改的SELECT語句,[查詢]結果被轉換爲XML。目前已經有一些私有的基於SQL的語言可用。通過簡單地使用嵌套的SELECT語句,就可直接轉換成符合對象 - 關係映射的嵌套的XML。或者使用SQL 3的對象視圖也可直接轉換成XML。最後還可使用 OUTER UNION 語句和特殊標記來決定怎樣將結果轉換成 XML。

除了這些私有語言以外,2000年一些公司聯合提出了 SQL 的 XML 擴展標準,現在已經成爲被稱爲 SQL/XML 的 ISO SQL 標準的一部分;最終可望於2003年得到批准。 SQL/XML 引入了一種 XML 數據類型,並且爲 SQL 增加了幾個函數,可以從關係型數據構造 XML 元素和屬性。

例如,下面的查詢

SELECT Orders.SONumber,
	XMLELEMENT(NAME "Order",
		XMLATTRIBUTES(Orders.SONumber AS SONumber),
		XMLELEMENT(NAME "Date", Orders.Date),
		XMLELEMENT(NAME "Customer", Orders.Customer)) AS xmldocument
FROM Orders

構造了具有兩個字段的結果集。第一個字段爲銷售訂單號,第二個字段爲一個 XML 文件。每一行有一個 XML 文件,它來自 Orders 表中相應的數據。例如,從訂單號 123 生成的 XML 文件是:

<Order SONumber="123">
	<Date>10/29/02</Date>
	<Customer>Gallagher Industries</Customer>
</Order>

在網上很難找到有關 SQL/XML 的資料。關於其介紹和(可能)過時的一些資料,請參考 SQLX Group 網站 。 最終的草案可從 SQL/XML 標準(PDF)得到。

5.2.3 XML Query Languages

基於模板和基於SQL的查詢語言只能用於關係數據庫,與此不同,XML查詢語言可用於任何XML文檔。爲了把它用於關係數據庫,必須把數據庫中的數據看作XML的模型,這樣才能對虛擬的XML文件進行查詢。

對於XQuery,基於表格的映射或對象-關係型映射都可以使用。當使用基於表格的映射時,各個表格被視爲單獨的文件,像SQL中的一樣, 這些表格的結合(joints)則在查詢[語句]本身中指明。如果使用的是對象-關係型映射,各個表格的層次被當作單個文件,而[表格的]結合在映射中說明。對於大多數關係數據庫而言,似乎基於表格的映射更爲常用,這是因爲它的實現似乎更簡單些,SQL的用戶對此也更爲熟悉。

如果使用XPath在多個表格中進行查詢,就必須使用對象-關係映射,這是因爲XPath不支持多個文檔的聯合。因此,如果使用基於表格的映射,也許每次只對一個表格進行查詢最好。

5.3 原生XML數據庫的數據存儲(Storing Data in a Native XML Database)

還可以將XML文件中的數據存儲在原生XML數據庫(native XML database)中。這麼做有幾個理由。首先,當你的數據是半結構化的數據時。也就是說,它的結構是普通的,但是如果將其映射到關係數據庫,結果是要麼出現大量空值(null)的字段,要麼表格的數量過多,浪費空間或效率低下。雖然半結構化的數據可存儲到面向對象的或層次型數據庫中,你還可以選擇將它以XML文件的形式存儲於原生XML數據庫。

將數據存儲在原生XML數據庫中的第二個理由是讀出速度。根據XML數據庫存儲數據的物理方式的不同,數據的讀出速度可以做到比關係型數據庫[的讀取速度]快得多。其原因是,原生XML數據庫對整個文件一起進行物理存儲,和[表示]文件各個部分的物理(而不是邏輯)指針可採用同一存儲策略。這就可以不使用連接(joins)或只使用物理連接讀取文件,無論哪種情況都比關係型數據庫所用的邏輯聯結要快。

以上述銷售訂單文件爲例。在關係型數據庫中,它可能被存爲四個表格 -- SalesOrders, Items, Customers, 和 Parts -- 讀取文件時需要將這些表格結合起來。在原生XML數據庫中,整個文件可被存儲在磁盤的一個地方,在讀取文件或其片斷時只需要一次查找和一次讀取操作。關係數據庫在讀取數據時則需要四次查找以及至少四次讀取操作。

這樣做的一個明顯缺點就是,只有數據的讀取順序和寫入磁盤的順序相同時,纔可以提高速度。如果你想要的數據視圖不同,比如只想要客戶及其訂單列表,性能可能比關係數據庫更差。所以,如果你的應用中是單個數據視圖爲主,爲了提高性能,纔可以考慮將數據存儲到原生XML數據庫。

將數據存儲在原生XML數據庫中的第三個理由是你想利用XML的獨有特性,如執行XML查詢。由於今天以數據爲中心的應用幾乎沒有這樣做的,而且關係數據庫正在逐步支持XML查詢語言,這個理由越來越不充分。

將數據存儲在原生XML數據庫中的一個問題是,大多數原生數據庫只能以XML[的形式]返回數據。(支持元素和屬性到應用程序變量綁定的只是少數)。如果你的應用程序需要另一種數據格式(很有可能),使用數據之前必須先解析XML。對本地的應用程序而言顯然是個缺點,而這種前期準備在(比如)ODBC中就不存在。對於將XML作爲數據載體使用的分佈式應用程序而言,這個問題不很嚴重,因爲不管用的是哪種數據庫,這種前期工作必須要有。

5.4 數據類型,空值,字符集,諸如此類 (Data Types, Null Values,Character Sets, and All That Stuff)

本節將就在傳統數據庫中存儲XML文件數據的相關問題展開討論。(有關數據類型和二進制數據存儲的討論同樣適用於原生XML數據庫)總的說來,你無法選擇數據交換軟件解決這些問題的方式。然而,你應當明白這些問題確實存在,這樣會有助於你選擇軟件。

5.4.1 數據類型 Data Types

如果單從字面上講,XML並不支持任何數據類型。除了非解析實體,XML文件中的所有數據都是文本,儘管它可能表示日期或整數等其他類型。一般來說,數據交換軟件負責把(XML文件中的)文本轉換成(數據庫中的)其他數據類型,反之亦然。

至於軟件如何確定該進行怎樣的轉換各不相同,常見的有兩種方法。第一種方法是軟件根據數據庫模型來確定數據類型,因爲它在運行時總是可用的。(而XML模型在運行時就不一定有,甚至根本就不存在)。第二種方法就是由用戶明確指定數據類型,比如映射信息。它可以由用戶寫出,或者自動從數據庫模型或XML 模型中產生。

類型轉換時的另一個問題是,究竟能夠識別(從 XML 轉換)或創建什麼文本格式。大多數情況下,能夠被識別爲特定數據類型的文本格式數目很有限,比如某個JDBC驅動程序支持單一的、特定的格式。日期看起來最容易出問題,因爲它的格式可能非常多。而數字在各種語言中的格式也不盡相同,也有可能出問題。

5.4.2 二進制數據 (Binary Data)

二進制數據在XML文件中的存儲方法一般有三種:非解析實體和Base64編碼(一種 MIME 編碼方式,將二進制數據映射到US-ASCII碼的一個子集[0-9a-zA-Z+/] - 見RFC 2045 );十六進制編碼(每二進制字節 用兩個十六進制字符[0-9a-fA-F]表示)以及非解析實體(二進制數據存儲在與該XML分離的物理實體內)。

二進制數據的最大問題在於數據轉換產品對它的支持不夠,所以要檢查你的軟件是否支持。另一個問題是,大部分(全部?)數據轉換產品都不存儲符號和實體聲明。這樣,將 XML 中的數據轉換到數據庫中時,與某些實體對應的符號就會丟失。(關於符號的更多信息詳見 XML 標準的 4.7 部分)。

5.4.3 空數據 (Null Data)

在數據庫術語中,空數據(null data)意味着沒有數據。這和值爲0的數字或長度爲零的字符串區別非常大。例如,假設你收集到 的是氣象數據,如果溫度計不能工作,則數據庫中存儲的就是null而不是0,否則情況就完全不同了。

XML也支持這種空數據的概念(通過可選(optional)元素或屬性)。如果一個可選元素或屬性的值爲空,就不會包含在文件內。而在數據庫中,值爲零長度字符串的屬性和空元素並不是null:它們的值爲零長度的字符串。

當你將XML文檔的結構映射到數據庫(或反過來)時,你當特別留意,可選元素類型或[空值]屬性會被映射到允許空值的字段(nullable columns),反之亦然。如果不是這樣的話,可能會產生插入錯誤(當轉換數據到數據庫時)或非法文件錯誤(從數據庫中取出數據時)。

與數據庫專業相比,XML社區對null含義的表示法更爲自由-- 特別是許多XML用戶都認爲零長度字符串的屬性和空元素是“空(null)”的,所以你應該檢查一下你的軟件是如何處理這種情況的。有些軟件爲用戶提供了選擇,可以定義XML中如何表示"null",以及支持XML Schema中的 xsi:null屬性。

5.4.4 字符集 (Character Sets)

根據定義,除了某些控制字符,XML文件可包含任何Unicode字符。不過,許多數據庫對Unicode的支持很有限或根本就不支持,而且需要特殊的配置才能處理非ASCII字符。如果你的文件包含非ASCII字符,要確保你的數據庫及數據轉換軟件對這些字符是否支持及如何支持的。

5.4.5 處理指令和註釋 (Processing Instructions and Comments)

處理指令和註釋並不是XML文檔“數據”的一部分,大多數(全部?)數據轉換軟件都不能處理它們。問題在於這些東西可能出現在XML文檔中的任何地方,所以不容易進行基於表格或對象-關係型映射。(一個明顯行不通的方案是爲這些處理指令和註釋建立一個表格,在其他表格加上指向這個表格的外部鍵(foreign key),每當處理別的表格時,就檢查這些表)。所以大多數數據轉換軟件會簡單地忽略它們。如果處理指令和註釋對你相當重要,就要檢查所用軟件對此能否處理及處理方法。或者可以考慮使用原生XML數據庫(native XML database)。

5.4.6 對標記的存儲 (Storing Markup)

正如5.1.2 一節所提到的, 有時候需要在數據庫中存儲混合內容的元素而無須進一步解析。這時, 標記被存儲爲標記字符(markup is stored with markup characters)。然而,問題出現在如何存儲那些不作爲標記使用的標記字符。在XML文檔中,這些是以 lt, gt, amp, quot 和 apos 實體存儲的。在數據庫中也可這麼做。例如,下面的description:

<description>
      <b>Confusing example:</b> &lt;foo/&gt;
   </description>

在數據庫中可存爲:

<b>Confusing example:</b> &lt;foo/&gt; 

這樣做的一個問題是一些非XML查詢語言,如SQL不會在表中搜尋標記和實體的用法並將其正確翻譯。這樣,如果你打算用SQL來搜索字符串“<foo/>”,你應當知道實際的搜索字符串是“&lt;foo/&gt;”。

另外,如果實體引用被擴展了,數據轉換軟件無法區別標記和實體。例如,如果上述例子在數據庫中按照下面的形式存儲,則軟件就無法知道<b> , </b> 和<foo/>到底是標記還是文本。

  <b>Confusing example:</b> <foo/>

解決這個問題的長久之計就是支持XML的數據庫(XML-aware database),在那裏,對真正的標記和看起來很像標記的東西的處理方式是不同的。非XML應用程序處理XML時,總是會出現這種問題。

5.5 從關係[數據庫]Schema產生DTD或相反 (Generating DTDs from Relational Schema and Vice Versa)

在XML文件與數據庫之間進行數據轉換時經常遇到的一個問題是如何從數據庫schema產生DTD或相反。在解釋如何做之前,必須指出這是設計階段的任務。其原因是大多數以數據爲中心的應用以及幾乎所有的盤點應用軟件(vertical applications)都是在已知的DTD或數據庫模型上工作的,因此,不會在運行時產生schema。再者,如下所述,schema的產生過程不十 分嚴格。如果應用程序需要在數據庫中隨機存放XML文件,則應考慮使用使用原生XML數據庫,而不是在運行時產生schema.

從DTD產生關係模型(或相反)的最簡單方法就是直接藉助於對象-關係映射,它有幾個可選特性。對於面向對象的數據庫也有相似的途徑。(關於每種方法的逐步演示,請看Mapping DTDs to Databases.)。

從DTD產生關係模型:

  1. 對每個複合數據類型, 創建一個表格和主鍵字段
  2. 對每個混合內容的元素類型,另外建一個表用來存儲PCDATA,通過其父表格的主鍵與父表格相連。
  3. 對該種數據類型的每個單值屬性,以及每個單次出現簡單子元素在表中建一個字段。如果子元素或屬 性是可選的,將該字段設置爲可爲空值的字段(nullable)。
  4. 對每個多值屬性(multi-valued attribute)和每個多次出現的簡單元素,單獨創建一個表,通過其父表格的主鍵與父表格相連
  5. 對每個複合類型的字元素,通過其父表格的主鍵將父表與該子元素類型的表相連。

從關係[數據庫]模型產生DTD:

  1. 爲每個表創建一種元素類型。
  2. 對錶中的每個數據(非鍵)字段以及主鍵字段,在元素類型上增加一個屬性或在內容模型上增加一個PCDADA型的字元素。
  3. 對於每個引用該主鍵的表格,在內容模型上增加一個子元素,繼續遞歸處理表格。
  4. 對於每個外來鍵,在內容模型上增加一個子元素,繼續遞歸處理外來鍵表格。

這些過程有一些不足,其中許多都可手工解決,比如名稱衝突及指定字段數據類型和長度。(DTD不包含數據類型信息,所以不可能預知數據庫中的數據類型。注意,從XML Schema文件可以預測數據類型和長度。)

更加嚴重的問題是,XML文件所用的數據“模型”通常和數據庫中所用的高效率的模型不同,(實際上更爲複雜)。請看如下XML片斷:

<Customer>
      <Name>ABC Industries</Name>
      <Address>
         <Street>123 Main St.</Street>
         <City>Fooville</City>
         <State>CA</State>
         <Country>USA</Country>
         <PostCode>95041</PostCode>
      </Address>
   </Customer>

從DTD產生關係模型的一般過程來看,通常會產生兩個表:一個是customers,另一個是addresses。然而,大多數情況下把 address存放在customer表中更爲合理。

<Address>元素就是包裝元素(wrapper element)的典型例子。採用包裝元素的原因有二:首先,這種結構使得文檔更容易理解;其次,它可作爲一種數據類型使用。例如,可以將<Address>元素傳給一個例程,該例程可以將所有地址轉換爲Address對象,不管它出現在哪裏。

雖然包裝元素在XML中很有用,但被映射到數據庫中的時候會增加額外的結構,很容易出問題。因此,在產生關係模型之前,一般應將其從DTD中除去。由於DTD一般是不允許改變的,而在映射是又不包含包裝元素,所以往往會導致實際文檔與數據轉換軟件所要求的文檔不匹配。對此可以在運行時轉換文件(比如使用XSLT):數據被轉到數據庫之前去掉包裝元素,轉出後在加上它。

儘管有這些不足,上述步驟還是爲DTD和關係模型之間的轉換提供了一個起點,對於大型系統尤爲如此。

6.0 文件的存取 (Storing and Retrieving Documents)

XML文件的存儲方式有兩大類:存儲於文件系統或作爲BLOB存儲於關係數據庫以獲得有限的XML功能,或者將其存儲於原生XML數據庫。

6.1 將文件存儲於文件系統 (Storing Documents in the File System)

如果你的文件比較簡單,數量不多,最簡便的方法就是存儲於文件系統。以後可以使用grep之類的工具進行查詢或sed來修改。(對XML文件進行全文檢索顯然不夠精確,比如很難區分文本和標記,而且無法理解實體的用法。然而,對於小型系統,這還是可以接受的)如果你想實現簡單的事務管理(transaction control),可以將文件放在諸如CVS或RCS等版本管理系統中。

6.2 將文件存儲於BLOB (Storing Documents in BLOBs)

另一種較爲複雜的方法就是將文件存儲於關係數據庫中的BLOB。這就利用了數據庫的一些優點:事務管理、安全、多用戶訪問等。此外許多關係數據庫提供的檢索工具可以進行全文檢索、近似檢索、同義詞檢索和模糊檢索。其中某些工具將會支持XML,這樣就可消除將XML文件作爲純文本檢索所帶來的問題。

如果以BLOB的形式存儲XML文件,即使數據庫不支持對XML的檢索,你也很容易實現自己的XML檢索。方法之一是創建兩個表:索引表(DB2中的side table)和文件表。文件表包含一個主鍵和一個存儲文件的BLOB字段,索引表內有一個已建立索引值字段以及一個外來鍵指向 文件表中的主鍵。

文件被存在數據庫中之後,就可以搜索所有已建索引的元素和屬性實例。每個實例及文件的主鍵都存於索引表中。這樣已建立索引的字段使應用程序可以快速檢索某個元素或屬性值並獲取相應的文件。

舉例來說,假如你有一些符合下列DTD的文件,希望建立作者的索引:

<!ELEMENT Brochure (Title, Author, Content)>
   <!ELEMENT Title (#PCDATA)>
   <!ELEMENT Author (#PCDATA)>
   <!ELEMENT Content (%Inline;)> <!-- Inline entity from XHTML -->

你可以用下表來存儲它:

   Authors                     Brochures
   ----------------------      ---------
   Author     VARCHAR(50)      BrochureID INTEGER
   BrochureID INTEGER          Brochure   LONGVARCHAR

假如你在數據庫中插入了一個brochure,程序就會在Brochures表中插入該 brochure,然後尋找<Author>元素,將它的值和brochure ID存入Authors表中。以後就可通過簡單的SELECT語句得到某個Author的所有brochure。比如想得到author爲Chen的所有 brochure,就可以執行下面的語句:

   SELECT Brochure
   FROM Brochures
   WHERE BrochureID IN (SELECT BrochureID FROM Authors WHERE Author='Chen')

更復雜的索引表可包含四個字段:元素類型或屬性名、(元素或屬性)類型、值和文件ID。這樣就可在一個表中存放多個標記[文件], 並按名字、類型和值建立索引。寫個操作這個表的SAX程序應該不是件難事。

6.3 原生XML數據庫 (Native XML Databases)

上述的簡單系統所提供的功能如果不能滿足你的需要,你可以考慮使用原生XML數據庫(native XML database)。原生XML 數據庫是專用於存儲XML文件的數據庫。和其他數據庫一樣,它支持事務管理、安全、多用戶訪問、編程API和查詢語言等。與其它數據庫的唯一區別就是其內部模型是基於XML的,而不是其他的模型--如關係模型。

原生XML數據庫常用於存儲以文檔爲中心的文件。主要原因是原生數據庫支持XML查詢語言,你可以對它提這樣的問題:“找出所有第三段內包含粗體字的文件”,用SQL顯然很難進行這樣的查詢。另外,原生XML數據庫保留了文件[元素?]順序、處理指令、註釋、CDATA塊以及實體引用等,而支持XML的數據庫(XML-enabled database)無法做到。

原生XML數據庫景常用於數據集成。以往都是通過關係數據庫的聯合來實現數據集成的,但這要求所有源數據都影射到關係模型,顯然對許多數據類型而言是不可行的,而XML數據模型提供了更好的靈活性,與關係數據庫相比,原生XML數據庫能更好地處理模型的更改,還可以處理無模型的數據。當需要集成的數據源不屬於你控制的時候,這些都是要着重考慮的。

原生XML數據庫的第三個用途是存儲半結構化數據,例如在財務和生物領域中,由於更改非常頻繁,以至於不可能有固定的模型,由於原生XML數據庫並不像關係數據庫那樣需要固定的模型,所以非常適合存儲此類數據,儘管它可能不需要供人閱讀。

原生XML數據庫最後一個主要用途是處理模型的改進。儘管原生XML數據庫本身並不提供完整的解決方案,但與關係型數據庫相比,有很大的靈活性。例如,原生XML數據庫不需要對現有的數據重新建立模型,能在沒有其他數據集成途徑時處理模型的改變,無需知道模型也能存儲數據。

原生XML數據庫的其他用途包括對耗時較長的交易提供數據和元數據緩存、處理大文件、處理層次性數據以及作爲中間層數據緩存。詳見原生XML數據庫案例

6.3.1 什麼是原生數據庫(Native XML Database)?

"native XML database" 這個術語首先在 Software AG 爲 Tamino 所做的營銷宣傳中露面。也許由於它的成功,後來這個術語在同類產品的開發商那裏成了通用叫法。它是一個營銷術語,從來沒有正式的技術定義,這是它的一個缺陷。

有一個接近的定義(出自XML:DB mailing list的一個成員)這樣定義原生XML數據庫(native XML database):

它爲 XML 文檔(而不是文檔中的數據)定義了一個(邏輯)模型,並根據該模型存取文件。這個模型至少應包括元素、屬性、PCDATA 和文件順 序。這種模型的例子有XPath數據模型、XML Infoset 以及 DOM 所用的模型和SAX 1.0的事件。

它以 XML 文件作爲其基本(邏輯)存儲單位,正如關係數據庫以表中的行作爲基本(邏輯)存儲單位。
它對底層的物理存儲模型模型沒有特殊要求。例如,它可以建在關係型、層次型或面向對象的數據庫之上,或者使用專用的存儲格式,比如索引或壓縮文件。

該定義的第一部分與其他類型數據庫的定義相似,都是關於數據庫所用的模型的。不過,原生 XML 數據庫所能存儲的信息比模型中定義的多。例如,它可支 持基於XPath 數據模型的查詢,但所用的存儲格式是純文本。CDATA 部分和實體用法也可存儲在數據庫中,但是模型中沒有包括。

定義的第二個部分是說原生數據庫的基本存儲單位是 XML 文件。看起來似乎也可存儲 XML 文件片斷,但幾乎所有的原生 XML 數據庫都是以文件方式存儲 的。

(基本存儲單位就是可以容納一份數據的最低級的上下文 (context),相當於關係數據庫中的行。它的存在並不妨礙以更小的數據單位來讀取數據, 比如文件片斷或個別元素,同樣也不影響將不同文件中的片斷進行組合。從關係數據庫的術語來講,相當於數據雖然以行的形式存放,並不意味着無法讀取某個字段 的值,或從現有的數據行創建新一行數據。)

該定義的第三部分講的是底層的數據存儲格式並不重要。確實如此,正如關係數據庫所使用的物理存儲格式與數據庫是不是關係型之間毫無關係。

6.3.2 原生XML數據庫的結構 (Native XML Database Architectures)

原生XML數據庫的結構可分爲兩大類:基於文本的和基於模型的。

6.3.2.1 基於文本的原生XML數據庫(Text-Based Native XML Databases)

基於文本的原生XML數據庫將XML作爲文本存儲。它可以是文件系統中的文件、關係數據庫中的BLOB或特定的文件格式。(事實上, 就其能力來說,一個增加了支持CLOB(Character Large Object)字段的XML處理功能的關係數據庫也可以是原生XML數據庫了。)

索引對所有基於文本的原生XML數據庫來說都是一樣的,它可以使查詢引擎很方便地跳到XML文件內的任何地方。這就可以大大提高數據庫存取文件或文件片斷的速度。這是因爲數據庫只需進行一次檢索、磁頭定位,再假如所讀的文件在磁盤上是連續[存儲]的話,只需一次讀盤就可讀出整個文件或文件片斷。相反,如果像關係數據庫或基於模型的原生XML數據庫那樣,文件由各個部分組合而成,就必須要進行多次查找定位和多次讀盤動作。

從這個意義上講,基於文本的原生XML數據庫與層次結構的數據庫很相似,當存取預先定義好層次的數據的時候,它比關係數據庫更勝一籌。和層次結構的數據庫一樣,當以其他形式比如轉置層次存取數據時,原生XML數據庫也會遇到麻煩。這個問題的嚴重程度尚未可知,很多關係數據庫都使用邏輯指針,使相同複雜度的查詢以相同的速度完成。由此看來這確實是個問題。

6.3.2.2 基於模型的原生XML數據庫 (Model-Based Native XML Databases)

第二類原生XML數據庫是基於模型的原生XML數據庫。它們不是用純文本存儲文件,而是根據文件構造一個內部模型並存儲這個模型。至於模型究竟怎樣存儲取決於數據庫。有些數據庫將該模型存儲於關係型和麪向對象的數據庫中,例如在關係型數據庫中存儲DOM時,就會有元素、屬性、PCDATA、實體、實體引用等表格。其他數據庫使用了專爲這種模型作了優化的專有存儲格式。

(Mark Birbeck 在 1998年12月的 XML-L 郵件列表中描述了一個建立在關係型數據庫上的簡單的、基於 模型的原生 XML 數據庫系統,該系統用了5個表 - 屬性定義、元素/屬性關聯、內容模型定義、屬性值、元素值 (PCDATA 或指向其它元素的指針),以及只包含元素、屬性、文本和文件順序的模型。參見 標題爲 "Record ends, Mixed content, and storing XML documents on relational database" 和 "storing XML documents on relational database"的信件。)

建立在其他數據庫之上的基於模型的原生XML數據庫的文件存取性能與這些數據庫相似,原因顯而易見:其存取要依賴這些數據庫。但是這個數據庫,特別是建立在其他數據庫之上的原生XML數據庫的設計有很大的變化餘地。例如直接以 DOM 方式進行對象-關係映射的數據庫系統在獲取節點的子元素時必須單獨執行 SELECT 語句。另一方面,這種數據庫大多對存取模型和軟件作了優化。例如 Richard Edwards 在 system for storing the DOM in a relational database一文中曾經描述只用一個SELECT語句就可獲取任意文件片斷(或整個文件)。

使用專用存儲格式的基於模型的原生XML數據庫如果以文件的存儲順序讀取文件,其性能與基於文本的原生XML數據庫相似。這是因爲這種數據庫大多在節點間使用了物理指針,這樣其讀取性能和讀取文本差不多。(究竟哪個快一些要取決於數據格式。如果返回文本格式,顯然基於文本的系統要快一些;如果希望返回的是DOM,假如該模型很容易映射到DOM,則基於模型的系統更快。)

與基於文本的原生XML數據庫一樣,如果數據的讀取順序和存儲順序不同,基於模型的原生XML數據庫很容易出現性能上的問題。這兩種類型的數據庫到底哪個快一些仍不是很清楚。

6.3.3 原生XML數據庫的特性 (Features of Native XML Databases)

本節簡單討論原生XML數據庫的一些特性,有助於大致瞭解其現狀和未來。

6.3.3.1 文件集 (Document Collections)

許多原生XML數據庫都支持集合(collection)的概念,其作用相當於關係數據庫中的表和文件系統中的文件夾,例如你想在原生XML數據庫中存儲銷售訂單,就可以定義一個銷售訂單的集合,這樣對銷售訂單的查詢就限於這個集合內的文件。

作爲另一個例子,假設你想把公司的所有產品的說明書存儲在原生XML數據庫中,在這種情形下,你要先定義一個層次結構。比如,爲每種產品定義一個集合,並在其中爲每種產品說明書的每個章節都指定一個集合。

這些集合是否被允許嵌套取決於所用的數據庫。

6.3.3.2 查詢語言 (Query Languages)

幾乎所有的原生XML數據庫都至少支持一種查詢語言。最常用的有 XPath (對多個文件的查詢作了擴充)和 XQL,以及很多專有的查詢語言。在考慮原生XML數據庫時應當確定其查詢語言是否滿足你的需要,比如從全文檢索到多個文件片斷的合併。

將來大多數原生XML數據庫大概都要支持W3C的XQuery。

6.3.3.3 更新和刪除 (Updates and Deletes)

原生XML數據庫對文件的更新和刪除方式有許多,從簡單的替換或刪除現有文件,到修改當前活動的 DOM 樹,以及用於指定如何修改文件片斷的語言。通常這些方法都是廠商專有的,不過也出現了兩種標準的XML文件更新語言:

  • 來自XML:DB Initiative 的 XUpdate,它是一種基於XML的語言,使用XPath確定節點集,然後指定刪除或插入操作,或在其前後插入新的節點。XUpdate已經在多個原生XML數據庫中實現。
  • W3C XQuery 工作組成員和Patrick Lehti已經提交了XQuery 擴展,並在一些原生XML數據庫中實現,很可能成爲 XQuery 更新的基礎。

儘管有了上述這些語言,但在XQuery包含更新功能之前,更新功能仍然難以統一。

6.3.3.4 事務、鎖定和併發 (Transactions, Locking, and Concurrency)

基本上所有的原生XML數據庫都支持事務處理(當然也應支持後退[rollback])。但是,鎖定通常是對整個文檔的而不是對文件片斷的,所以多用戶併發性[的支持]相對較低。問題的大小取決於應用程序以及“文件”的構成。 例如:

  • 用戶手冊分成幾個章節,每個章節都是一個文件,這時併發問題就小一些,因爲兩個作者同時對同一章節進行更新的情況不大可能發生。
  • 如果整個公司的銷售數據都放在同一個文件中,文件級的鎖定很容易造成災難性的後果。因爲兩個銷售人員更新同一個產品信息的機會相當大。不過至少可以爲每個潛在的客戶創建一個文件來部分地解決這個問題。
  • 文檔包含的數據用在工作流-例如財務合同中。其中每一步都需要從文檔中讀取數據並加入自己的數據。例如有時要檢查信用情況並添加信用記錄,而另一步要檢查同一個客戶的合同結餘並添加到總的結餘。如果使用節點級的鎖定,有些步驟可能會以並行的方式執行。如果採用文檔級的鎖定,則必須按照順序執行以避免衝突。如果是大規模的應用則可能造成難以接受的延遲。

節點級鎖定的問題在於如何實現。通常鎖定節點也要鎖定其父元素,以此類推,鎖定根元素,也就是鎖定整個文檔。假設某個交易要讀取子節點,如果不鎖定祖先節點的話,另一項交易可能會刪除它的祖先節點,進而刪除該節點。然而,如果另一個交易要更新的節點不在同一個分支上,就沒有問題。

Stijn Dekeyser, et al 提出了該問題的一個 部分解決方案,儘管沒有完全避免鎖定目標節點的祖先節點.但通過通過查詢標記出鎖定節點到目標節點的路徑,靈活地進行鎖定,這樣可以使其他交易確定是否與已經鎖定的交易發生衝突。(由於通過計算查詢獲取鎖定結果代價很高,其實用性不像所描述的那麼高,但不失爲一個普通的方法)。見XML / Database 鏈接 中的Academic Papers部分。少數幾個原生XML數據庫實現了節點級鎖定,但具體實現方式尚不清楚。

將來,大多數的原生數據庫應該會提供節點級的鎖定。

6.3.3.5 應用程序接口 (Application Programming Interfaces ,APIs)

幾乎所有原生數據庫都提供編程接口API。這種API很像ODBC,並提供有連接到數據庫、瀏覽元數據、執行查詢和返回結果的方法 (methods)。返回結果通常是XML字符串、DOM樹、返回文檔的SAX解析器或XMLReader。如果查詢返回結果是多個文檔的話,通常都會提 供例舉(iterating)這些結果的方法。大多數原生XML數據庫提供的都是專屬的API,不過也有非專屬的API:

  • 來自 XML:DB.org 的 XML:DB API編程語言無關,使用XPath作爲查詢語言,正在進行支持XQuery的擴充。已經在數個原生XML數據庫中實現。
  • JSR 225: XQuery API for Java (XQJ) 基於JDBC,使用XPath作爲查詢語言,是由Sun的JCP開發的,並有了草案。由於其始創者是IBM和Oracle,很可能被廣泛採用。

大多數原生數據庫還有將查詢結果通過 HTTP 返回的能力。

6.3.3.6 “往返車票”(Round-Tripping)

原生XML數據庫的一個重要特性是它可以爲XML文檔提供了“往返車票(round-trip)”。就是說你可以將XML文件存放在原生XML數據 庫中,而且再取回“同樣的”文件。對於以文檔爲中心的應用程序來說非常重要,因爲CDATA部分、實體用法、註釋和處理指令是這些文檔不可缺少的組成部分。特別是對於法律和醫學文件,按規定這些文檔必須要保持原樣。

(對於以數據爲中心的應用來說,由於它主要關心的是元素、屬性、文本以及層次順序,這種“往返車票”顯得不是很重要。能夠在XML文件和數據庫之間交換數據的軟件都可以處理這些往返問題,如果同級元素的順序對以數據爲中心的應用程序來說很重要,在有限幾種情況下也可以保留這種順序。但是由於它[指一般的交換軟件--譯者注]一般不保留兄弟元素的順序,也不確保原樣保持處理指令、註釋以及物理結構(實體引用、CDATA等等),所以不適於以文檔爲中心的應用。)

所有原生XML數據庫都能夠在元素、屬性、CDATA和文件順序的級別上爲文件提供“往返車票”,至於究竟能達到什麼程度取決於數據庫。一般來說,基於文本的原生XML數據庫能夠原樣存取XML文件,而基於模型的原生XML數據庫只能在文件模型的級別上原樣存取XML文件。對於特別小的文檔模型,意味着比普通的XML原樣存取的級別低。

由於你的應用程序要求決定了應當在哪個級別原樣存取,所以對原生XML數據庫的選擇餘地可能很大,也可能很小。

6.3.3.7 外部數據 (Remote Data)

某些原生XML數據庫可包含有外部數據,這些外部數據來自存儲在數據庫中的文檔。通常這些數據通過ODBC、OLE DB或JDBC從關係數據中取出,模型可以是基於表格的或對象-關係型映射。原生XML數據庫決定了這些數據是不是即時的(live)--即原生XML數據庫中文檔的更新是否在外部數據庫中反映出來。大多數原生XML數據庫大概最終都會支持即時的外部數據。

6.3.3.8 索引 (Indexes)

幾乎所有的原生XML數據庫都支持元素和屬性的索引。像非XML數據庫一樣,索引用於提高檢索速度。

6.3.3.9 外部實體存儲 (External Entity Storage)

XML文檔存儲時的一個棘手問題就是怎樣處理外部實體。也就是說,應當將其展開,把它的值存儲在文件中,還是保留實體引用原封不動?這個問題沒有統一的答案。

例如,假設文檔中包含一個外部實體用來調用一個當前天氣報告的CGI程序。如果將這個文件用於提供天氣預報的網頁,那麼將這個實體展開就是錯誤的,因爲網頁中提供的不是即時的數據。相反,如果文件是氣象歷史資料的一部分,那麼不展開它反而是不對的,否則文件總是含有當前的數據而不是歷史資料了。

再看另外一個例子,假設一個產品手冊只包含指向手冊中其他章節的外部實體引用。如果這些章節又被其他文件(比如該產品的另一種型號的手冊)使用,那 麼展開這些引用就不對了,因爲這會造成同一個章節有多份拷貝。

我不知道原生XML數據庫如何處理這個問題。最理想的當然是允許你根據不同情況指定是否展開外部實體引用。

6.3.4 規範化,引用完整性和可伸縮性 (Normalization, Referential Integrity, and Scalability)

對許多人,特別是有關係型數據庫背景的人來說,由原生XML數據庫引發出不少爭論,特別是圍繞數據的存儲方面(相對於文檔而言)。這裏我們就來討論這些話題。

6.3.4.1 規範化 (Normalization)

規範化指的是數據庫模型的設計當中要保證每一份數據只能存儲一次。規範化有幾個好處,例如可以減少磁盤空間佔用,消除可能的數據不一致性。這是關係型數據庫技術的基礎之一,也是人們在討論原生XML數據庫的數據存儲時的熱點問題。

在進一步討論規範性之前,需要指出對許多以文檔爲中心的文件這不是大問題。例如有一些描述公司產品信息的文件,通常各個文件的公用數據很少--比如版權聲明、公司地址和電話號碼、產品標誌等等,其數量相對來說太小了,幾乎沒有人考慮它的存儲規範性。(但是,其他種類的文檔可能有許多重疊內容,有必要進行規範 化)。

與關係型數據庫一樣,原生XML數據庫並不要求你一定要規範你的數據,用原生XML數據庫你也很容易設計出一個糟糕的存儲結構。所以在將文件存入原生XML數據庫之前,你應仔細考慮文檔的結構。(與關係型數據庫相比,原生XML數據庫在這點有些優勢。因爲原生XML數據庫沒有數據庫模式,你可以同時以多種模式存儲相似的文件,不過爲了簡化事務處理,你可能需要重新設計查詢並轉換你的文件(這相對並不重要))

原生XML數據庫的規範化和關係型數據庫的規範化差不多一樣:你的文檔的設計要保證不會有重複數據。兩者的不同在於XML支持多值屬性而(大多數)關係型數據庫不支持。這樣就有可能以一種在關係型數據庫中無法實現的方式來“規範”原生XML數據庫的數據。

例如銷售訂單,它含有頭信息比如訂單編號、日期和客戶代碼,還有具體項目如零件號、數量和總價。在關係型數據庫中,頭信息和具體項目必須存在於不同 的表內。而在原生XML數據庫中,這些信息可以存儲在同一個文件內,不會產生冗餘,因爲XML與生俱來就支持一個父元素內包含多個子元素。

不幸的是,現實當中的規範化可沒這麼簡單。例如你想要銷售訂單包含客戶信息如合同名稱、收貨和付款地址,該怎樣做? 你有兩種選擇:第一,你可以在銷售訂單中複製一份客戶信息,結果帶來數據冗餘和其他問題;第二,你可以單獨存儲客戶信息,在銷售訂單中提供一個指向客戶信息文件的XLink,或者在查詢時再將這兩個文件連接起來。這就要求對XLink的支持(雖然正在計劃,但大多並不支持)或者查詢語言要支持聯合[joins](同樣並不總能如願)。

在實踐當中答案尚不明確。實際當中出於性能的考慮,數據並不總是規範的,所以有一些不規範的XML數據並不像初看起來那麼糟糕,不過你必須做出抉擇。如果你存儲的是以文檔爲中心的文件並且在相當程度上做到了規範化,比如將章節或過程單獨存儲並將它們連接起來創建最終用戶所用的文件,那麼原生XML數據庫可能就是一個不錯的解決方案,尤其是它能提供別的數據庫中所沒有的特性比如XML查詢語言。如果你要存儲的文件是以數據爲中心的,而原生XML數據庫能夠改進應用程序的性能,或者它提供的半結構化數據存儲,而在別的數據庫中是無法實現的,你也應當用原生XML數據庫。如果你只不過想在原生XML數據庫內實現一個關係型數據庫,你就應該反思一下,爲什麼不把關係型數據庫列爲首選。

6.3.4.2 引用完整性 (Referential Integrity)

與規範性密切相關的是引用完整性(referential integrity)。引用完整性即相關數據的[引用]指針的有效性,是 保持數據庫數據一致性的必要條件。如果你的銷售訂單含有一個客戶代碼,而相應的客戶信息並不存在,這對你沒什麼好處。發貨部門不知道往哪裏發貨,而財務部 門不知道給哪裏寄發票。

在關係型數據庫中,引用完整性意味着確保外部鍵指向合法的主鍵,也就是說,對每個外部鍵都要檢查相應的主鍵記錄。在原生XML數據庫中,引用完整性 意味着XLink或其他專有鏈接機制指向合法的文件或文件片斷。

XML 文件中的指針有多種形式:ID/IDREF 屬性,key/keyref 域(在 XML Schema 中定義),XLink 以及各種私有機制。後者包括語言相關的“referencing”元素和屬性,例如 XML Schema 中 <element>元素的 ref 屬性,以及特定數據庫的鏈接機制。而語言相關的“referencing” 元素比較普遍,數據庫特定的鏈接機制較爲少見。

原生 XML 數據庫的引用完整性可分爲兩大類:內部指針(同一文件內的指針)的完整性和外部指針(不同文件之間的指針)的完整性。使用非標準機制實現的內部指針的引用完整性一向難以達到,因爲原生 XML 數據庫無法識別此類指針。以標準機制比如 ID/IDREF 或 key/keyref 實現的內部引用完整性至少可通過驗證獲得部分支持。

之所以說部分支持,是因爲大多數原生 XML 數據庫僅在將文件存入數據庫時才進行驗證。這樣,如果更新發生在文件級 - 即刪除和替換文件,驗證已足以確保內部指針的完整性。但是如果更新發生在節點一級 -即插入、修改和刪除節點,則數據庫必須執行額外的工作(比如校驗所有的變化)來確保內部指針的引用完整性。支持該功能的原生 XML 數據庫極少(如果有的話)。

對外部指針的引用完整性(據我所知)仍未有支持,甚至支持外部指針的數據庫都很罕見。假如某個外部指針指向了數據庫中的其他資源,沒有理由不保證其完整性,但如果指向了數據庫之外的資源,這種保證的缺乏尚有情可原。例如,某個文件內的一個 XLink 指向了外部網站的某個文件,數據庫顯然無法知道後者是否存在,因而也就無法保證該 XLink 的完整性。

將來,許多原生XML數據庫大致都會以標準的機制支持內部指針的引用完整性。許多原生 XML數據庫大約都會在某種程度上支持外部指針,以及支持指向同一個數據庫中的資源的外部指針的引用完整性。而在目前,多數情況下還有賴於應用程序保證(內部或外部)指針的完整性。

6.3.4.3 可伸縮性 (Scalability)

可伸縮性完全不是我的所長,所以下面大多都是我的推測。總的來說,我想原生XML數據庫的可伸縮性在某些環境下會非常好,而其他場合下可能非常糟糕。

與層次型和關係型數據庫類似,原生XML數據庫也使用索引來查找數據。這就意味着文件(或文件片斷)的查找只與索引的大小有關,而與文件的大小和數量無關,因而原生XML數據庫定位文件開始的速度和其他使用同一種索引技術的數據庫一樣。由此看來,原生XML數據庫的可伸縮性和其他數據庫一樣。

與層次型數據庫相同而與關係型數據庫不同的是,許多原生XML數據庫用物理方法鏈接相關數據。特別是基於文本的原生XML數據庫用物理的方法對相關數據分組,使用專用存儲格式的基於模型的原生XML數據庫通常使用物理指針來對相關數據分組。(建立在關係數據庫之上基於模型的原生XML數據庫使用的是 邏輯鏈接。)

由於物理鏈接比邏輯鏈接速度快,原生XML數據庫和層次型數據庫一樣,數據的讀出速度比關係型數據庫快得多。因此,從數據的讀取方面來看,它應具有同樣的可伸縮性。事實上,在數據的讀取能力上XML數據庫比關係型數據庫甚至更好,因爲可伸縮性與初次索引查找有關,而不是關係型數據庫所用的多次查找。(需要指出,關係型數據庫也以集簇索引(clustered indexes)的形式提供數據的物理鏈接。不過,這種鏈接是應用於各個表格而不是整體層次上的。)

令人遺憾的是這種可伸縮性是有限的。就像層次型數據庫,原生XML數據庫中所用的物理連接只能作用於特定的層次。也就是說,如果數據的讀取和數據的存儲在同一層次下,則讀取速度很快,否則就不一定快。例如將客戶信息存儲在各個銷售訂單文件中,則讀取銷售訂單時的速度很快,而如果需要的數據視圖不同,比如要找出某個客戶的所有訂單將會很慢,因爲此時物理連接已不再適用。)

爲了緩解這個問題,原生XML數據庫大量使用了索引,經常對所有元素和屬性都作了索引。這雖然有助於減少讀取時間,卻增加了更新時間,因爲維護這種索引的代價很高。在只讀的環境下這無關緊要,在交易頻繁的環境下可能造成麻煩。

最後,對於未索引數據的查找來說,原生XML數據庫的可伸縮性比關係型數據庫差的多。此時這兩種數據庫都要線性地查找數據,而原生XML數據庫的情況更爲糟糕,因爲它的數據不是完全規範的。比如你要查找某個日期的所有銷售訂單,而日期是未經索引的。如果用的是關係型數據庫,就要讀取所有OrderDate字段的值,而對於原生XML數據庫,這意味着要讀取每個銷售訂單文件,並從中查找<OrderDate>元素。不但需要讀取<OrderDate>元素的內容;而且還要讀取所有其它文件的內容。對於基於文本的原生XML數據庫,情況也很不妙:在與目標日期比較之前,必須先對文本進行解析並轉換爲日期格式。

那麼對你來說,可伸縮性是否嚴重?這完全取決於你的應用。如果你的應用程序中所需的數據一般都和其存儲形式相同,則原生XML數據庫的可伸縮性應是不錯的。許多以文本爲中心的應用就屬於這種情形。例如組成產品手冊的文檔幾乎總是作爲整體讀取的。反之,如果你的應用中數據視圖不是很確定,則可伸縮性有可能出問題。

對於原生XML數據庫的討論就到此結束。在接下來的兩部分中,我們將考察兩種特殊的原生XML數據庫:可持久化DOM和內容管理系統。

6.4 可持久化DOM (Persistent DOMs, PDOMs)

可持久化DOM(persistent DOM)或PDOM是在某種持久性存儲[介質]上實現了DOM 的一種特殊的原生XML數據庫。與大多數以DOM樹返回文檔的原生XML數據庫不同,PDOM返回的DOM是實時的(live)。也就是說,對DOM所作 的改變直接反映在數據庫中。(這種改變實際上是否馬上做出或者通過調用一個方法來實現取決於數據庫)大多數原生XML數據庫返回個應用程序的DOM樹是一個複製品,而數據庫中的改變是通過XML更新語言,或者是通過替換整個文件來實現的。

由於PDOM樹是實時的,數據庫通常是在本地。這就是說,它和應用程序在同一個進程空間,或者至少在同一部機器(儘管這並不是必需的)。這是出於性能上的考慮,因爲外部數據庫上的PDOM必須經常向遠程服務器發出請求。

PDOM在DOM應用程序中所起的作用和在面向對象的應用程序中面向對象的數據庫的作用一樣:它爲應用程序的數據提供了可持久化的存儲,也可作爲應用程序的虛擬內存。後一種作用對於操作大型文件的DOM應用來說有着特殊的重要性,因爲DOM與XML文件長度之比很容易超過10。(實際的係數取決於文件中文本的平均長度,文本的平均長度較小的文件其係數較高。)

6.5 內容管理系統 (Content Management Systems)

內容管理系統是原生XML數據庫的另一種特殊形式。它們是爲管理手工寫成的文件例如用戶手冊和技術草稿(white paper)而專門設計的,並且建立在原生XML數據庫之上。這個數據庫一般是處於用戶看不到的後臺,而提供給用戶的功能有:

  • 版本和訪問控制。
  • 搜索引擎。
  • XML/SGML編輯器。
  • 發佈引擎。比如以書面、CD形式或在Web上發佈。
  • 內容與樣式的分離。
  • 可通過腳本或編程擴展。
  • 數據庫數據的集成(integration)。

相對於文件管理系統,內容管理系統這個術語道出了這樣的事實:它使你可以將文件分爲離散的片斷(比如示例、過程、章節或旁註)和元數 據(例如作者、修訂日期、文件編號),而不是以整體管理文件。這不但簡化了一個文件多個作者時的協調工作,而且能使你從現有文件部分組合成全新的文件。

7.0 XML 數據庫產品 (Database Products)

關於最新的XML數據庫產品,參見XML Database Products.

8.0 相關鏈接 (Additional Links)

有關XML/數據庫的相關資源,包括軟件和文章,參見XML / Database Links

9.0 意見和反饋 (Comments and Feedback)

請將意見和反饋發送給Ronald Bourret [email protected]。 我經常外出旅行,有可能延誤兩到三個星期。

感謝Michael Champion, John Cowan, Marc Cyrenne, Marc de Graauw, Kelvin Ginn, Ingo Macherius, Lars Martin, Nick Leaton, Evan Lenz, Michael Rys, Walter Perry, Kimbro Staken, Jim Tivy, Phillipe Vauclair, Dylan Walsh, Irsan Widarto, Morten Primdahl 及其他人的意見和耐心。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章