XML與數據庫
2.0 XML是數據庫嗎?(Is XML a Database?) 如果僅按數據庫這個術語的本質來看,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用作數據交換。那么你的數據最好有個非常規則的結構并且可供非XML程序使用。還有,XML文檔所用的某些東西如實體和編碼對你來說并不重要 --總之,你感興趣的是數據,而不是它在XML內如何存儲。在這種情況下,你大概需要一個關系型數據庫以及在XML和數據庫之間轉換數據的軟件。如果你的應用程序是面向對象的,你甚至還需要一個在數據庫或XML中存取這些對象的系統。 另一方面,假如你要從一些結構松散的XML文檔建立一個網站。你不但要管理這個網站,還要提供站點內容搜索。你的文檔看起來結構比較松散,其中的實體的使用對你來說可能更重要,因為它們是文檔結構的重要部分。這種情況下,你也許需要一個原生XML數據庫(native XML database)或內容管理系統(content management system)。這使你可以保持文檔的物理結構,支持文件級的事務處理,以及使用XML Query語言進行查詢。 4.0 數據和文檔 (Data versus Documents) (歷史背景:我在xml-dev郵件列表上第一次聽說data-centric和document-centric這些術語,不知道是誰發明的,但是我在1997的消息中發現有使用document-centric的,從1998年以后這兩個術語都有使用。) 4.1 以數據為中心的文檔 (Data-Centric Documents) 以數據為中心的文檔的特點是結構相當規整,數據粒度精細(fine-grained data)(即最小的獨立數據單位只存在于PCDATA元素或屬性這一級別),很少或沒有混合內容。除非在對文檔進行驗證的時候,同級元素或PCDATA的出現次序一般來說并不重要。 以數據為中心的文檔中的這類數據可以來自數據庫(此時要輸入給XML)或在數據庫之外(此時要將其存入數據庫)。前者的一個例子就是關系數據庫現存的大量數據;而從測量系統采集并轉化為XML的科研數據就是后者的例子。 例如,下面的銷售訂單就是以數據為中心的: <SalesOrder SONumber="12345"> 例如,下面是個描述航班信息的文檔: <FlightInfo> <Flights> 以文檔為中心的文檔通常是以XML手工寫成,或從其他格式(如RTF, PDF, SGML)轉換到XML,與以數據為中心的文檔不同,它們的來源通常不是數據庫。(將數據插入到模板而得到的文檔是以數據為中心的;更多信息請看4.1節末尾部分)。將各種格式轉換為XML的軟件信息,請參閱XML軟件相關鏈接。 例如,下面這個產品說明是以文檔為中心的: <Product> <Intro> <Description> <Para>The turkey wrench, which comes in <i>both right- and left- 除此之外,弄清文件的這兩種特點有助于選擇數據庫的類型。一般來說,將數據存儲于傳統的數據庫,例如關系型,面向對象型或層次型數據庫。這可由第三方的中間件完成或由數據庫本身提供內在支持。對于后者,該數據庫被稱作支持XML的(XML-enabled)。文檔可被存儲在原生(native)XML數據庫(專為存儲XML而設計的數據庫)或內容管理系統(建在原生XML數據庫之上專門用來管理文檔的程序)。 這些原則并不是絕對的。如果對XML特有的功能不很看重,數據,特別是半結構化的數據可以存儲在原生XML數據庫,文檔也可以存儲到傳統數據庫。何況傳統數據庫與原生XML數據庫之間的界限越來越模糊,傳統數據庫增加了原生XML的能力,而原生XML數據庫增加了對文檔存儲在外部(通常為關系型)數據庫的支持。 本文剩下的部分就有關數據(第5節)和文檔(第6節)的存儲和讀取的策略與問題展開討論。關于最新的XML數據庫產品,請見XML數據庫產品。 5.0 數據的存取(Storing and Retrieving Data) 對于后者,文檔的結構必須完全符合映射所要求的結構。由于通常不易做到這點,使用這種策略的產品一般要和XSLT一起使用。在數據轉換到數據庫之前,先將文件按照映射所要求的結構進行轉換,然后轉存數據。相應地,數據從數據庫中取出以后,結果文件要被轉換成應用程序所需的結構。 5.1 映射[XML]文件Schema到數據庫Schema (Mapping Document Schemas to Database Schemas) 這種方法的一個后果是能否保證文件有“往返車票” -- 將文件中的數據存入數據庫后,又從數據庫中的數據重新構建文件,得到的文件往往和原來的文件不同(哪怕從最簡單的角度來講)。這種情形是否可以接受取決于你的要求,在選擇軟件時要考慮到這一點。 將一個XML文件的schema映射到數據庫的schema有兩種方法:基于表格的映射和對象-關系映射。 5.1.1 基于表格的映射 (Table-Based Mapping) <database> 基于表格的映射對存取關系型數據比較適用,比如在兩個關系型數據庫之間轉換數據。其明顯不足就是不適于格式不符的XML文件。 5.1.2 對象-關系映射 (Object-Relational Mapping) (所謂“對象-關系映射”有些名不副實。因為對象樹可以被直接映射到面向對象型和層次型數據庫,然而,但是由于大多數使用這種映射方式的主流產品使用的其實是關系型數據庫,所以“對象-關系映射”也就廣為人知。) 我們在理解這種映射所用的對象模型的時候要知道,這個對象模型不是文件對象模型(DOM)。所有XML文件的DOM都是一樣的,而上述描述文件數據的模型對于每個DTD所定義的XML文件都不一樣,例如,上述銷售訂單的模型是一個由四個類所組成的對象樹--SalesOrder, Customer, Item, 和Part, 如下圖所示: SalesOrder 元素 --- 屬性 (根據Sun的 Java Architecture for XML Binding,XML文件與對象的綁定通常被稱為XML數據綁定(XML data binding),有些產品支持XML數據綁定,其中許多還可以在對象和數據庫之間進行數據交換,更多的信息,請看 XML數據綁定相關資源 XML Data Binding Resources.) 各種產品對對象-關系映射的具體支持各不相同。例如: 所有產品都支持從復合元素類型到類,以及從簡單元素類型和屬性(attributes)到[類的]屬性(properties)的映射。 當使用基于表格的映射的XML文件有多個表格組成時,這個包裝元素就相當于<database>元素,他的存在只是為了滿足 XML 文件只能有一個根元素的要求。少數產品允許你就像指定包裝元素那樣,在較低的層次上指定[某些元素是否被映射 -譯注]。 大多數產品允許你說明將[對象的]屬性(properties)映射到XML文件中的屬性(attribute)還是子元素。某些產品還允許你混合使用屬性和子元素,其他的只允許你使用兩者之一。 5.2 查詢語言(Query Languages) 這個問題的長久解決方案就是設計一種可以返回XML[文件]的查詢語言。目前來看(2002年11月),大多數這種語言都依賴于在模板中嵌入 SELECT 語句。到 XQuery 最后定稿時這個局面有望得到改變,正如主流的數據庫產品提供商已經做的那樣。不幸的是,幾乎所有的XML查詢語言(包括 XQuery1.0 和 SQL/XML的最初發布版本)對文件都是只讀的,所以短期來說,最需要的是能夠插入、更新、刪除數據的手段。(從長遠來看,XQuery 和 SQL/XML 將會增加這種功能。) 5.2.1 基于模板的查詢 (Template-Based Query) <?xml version="1.0"?> <?xml version="1.0"?> 可以將返回結果放在輸出文件中的任何地方,包括作為后續SELECT語句的參數。 5.2.2 基于SQL的查詢語言 (SQL-Based Query Languages) 除了這些私有語言以外,2000年一些公司聯合提出了 SQL 的 XML 擴展標準,現在已經成為被稱為 SQL/XML 的 ISO SQL 標準的一部分;最終可望于2003年得到批準。 SQL/XML 引入了一種 XML 數據類型,并且為 SQL 增加了幾個函數,可以從關系型數據構造 XML 元素和屬性。 例如,下面的查詢 SELECT Orders.SONumber, <Order SONumber="123"> 5.2.3 XML Query Languages 對于XQuery,基于表格的映射或對象-關系型映射都可以使用。當使用基于表格的映射時,各個表格被視為單獨的文件,像SQL中的一樣, 這些表格的結合(joints)則在查詢[語句]本身中指明。如果使用的是對象-關系型映射,各個表格的層次被當作單個文件,而[表格的]結合在映射中說明。對于大多數關系數據庫而言,似乎基于表格的映射更為常用,這是因為它的實現似乎更簡單些,SQL的用戶對此也更為熟悉。 如果使用XPath在多個表格中進行查詢,就必須使用對象-關系映射,這是因為XPath不支持多個文檔的聯合。因此,如果使用基于表格的映射,也許每次只對一個表格進行查詢最好。 5.3 原生XML數據庫的數據存儲(Storing Data in a Native XML Database) 將數據存儲在原生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) 5.4.1 數據類型 Data Types 至于軟件如何確定該進行怎樣的轉換各不相同,常見的有兩種方法。第一種方法是軟件根據數據庫模型來確定數據類型,因為它在運行時總是可用的。(而XML模型在運行時就不一定有,甚至根本就不存在)。第二種方法就是由用戶明確指定數據類型,比如映射信息。它可以由用戶寫出,或者自動從數據庫模型或XML 模型中產生。 類型轉換時的另一個問題是,究竟能夠識別(從 XML 轉換)或創建什么文本格式。大多數情況下,能夠被識別為特定數據類型的文本格式數目很有限,比如某個JDBC驅動程序支持單一的、特定的格式。日期看起來最容易出問題,因為它的格式可能非常多。而數字在各種語言中的格式也不盡相同,也有可能出問題。 5.4.2 二進制數據 (Binary Data) 二進制數據的最大問題在于數據轉換產品對它的支持不夠,所以要檢查你的軟件是否支持。另一個問題是,大部分(全部?)數據轉換產品都不存儲符號和實體聲明。這樣,將 XML 中的數據轉換到數據庫中時,與某些實體對應的符號就會丟失。(關于符號的更多信息詳見 XML 標準的 4.7 部分)。 5.4.3 空數據 (Null Data) XML也支持這種空數據的概念(通過可選(optional)元素或屬性)。如果一個可選元素或屬性的值為空,就不會包含在文件內。而在數據庫中,值為零長度字符串的屬性和空元素并不是null:它們的值為零長度的字符串。 當你將XML文檔的結構映射到數據庫(或反過來)時,你當特別留意,可選元素類型或[空值]屬性會被映射到允許空值的字段(nullable columns),反之亦然。如果不是這樣的話,可能會產生插入錯誤(當轉換數據到數據庫時)或非法文件錯誤(從數據庫中取出數據時)。 與數據庫專業相比,XML社區對null含義的表示法更為自由-- 特別是許多XML用戶都認為零長度字符串的屬性和空元素是“空(null)”的,所以你應該檢查一下你的軟件是如何處理這種情況的。有些軟件為用戶提供了選擇,可以定義XML中如何表示"null",以及支持XML Schema中的 xsi:null屬性。 5.4.4 字符集 (Character Sets) 5.4.5 處理指令和注釋 (Processing Instructions and Comments) 5.4.6 對標記的存儲 (Storing Markup) <description> <b>Confusing example:</b> <foo/> 另外,如果實體引用被擴展了,數據轉換軟件無法區別標記和實體。例如,如果上述例子在數據庫中按照下面的形式存儲,則軟件就無法知道<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) 從DTD產生關系模型(或相反)的最簡單方法就是直接借助于對象-關系映射,它有幾個可選特性。對于面向對象的數據庫也有相似的途徑。(關于每種方法的逐步演示,請看Mapping DTDs to Databases.)。 從DTD產生關系模型: 對每個復合數據類型, 創建一個表格和主鍵字段 為每個表創建一種元素類型。 更加嚴重的問題是,XML文件所用的數據“模型”通常和數據庫中所用的高效率的模型不同,(實際上更為復雜)。請看如下XML片斷: <Customer> <Address>元素就是包裝元素(wrapper element)的典型例子。采用包裝元素的原因有二:首先,這種結構使得文檔更容易理解;其次,它可作為一種數據類型使用。例如,可以將<Address>元素傳給一個例程,該例程可以將所有地址轉換為Address對象,不管它出現在哪里。 雖然包裝元素在XML中很有用,但被映射到數據庫中的時候會增加額外的結構,很容易出問題。因此,在產生關系模型之前,一般應將其從DTD中除去。由于DTD一般是不允許改變的,而在映射是又不包含包裝元素,所以往往會導致實際文檔與數據轉換軟件所要求的文檔不匹配。對此可以在運行時轉換文件(比如使用XSLT):數據被轉到數據庫之前去掉包裝元素,轉出后在加上它。 盡管有這些不足,上述步驟還是為DTD和關系模型之間的轉換提供了一個起點,對于大型系統尤為如此。 6.0 文件的存取 (Storing and Retrieving Documents) 6.1 將文件存儲于文件系統 (Storing Documents in the File System) 6.2 將文件存儲于BLOB (Storing Documents in BLOBs) 如果以BLOB的形式存儲XML文件,即使數據庫不支持對XML的檢索,你也很容易實現自己的XML檢索。方法之一是創建兩個表:索引表(DB2中的side table)和文件表。文件表包含一個主鍵和一個存儲文件的BLOB字段,索引表內有一個已建立索引值字段以及一個外來鍵指向文件表中的主鍵。 文件被存在數據庫中之后,就可以搜索所有已建索引的元素和屬性實例。每個實例及文件的主鍵都存于索引表中。這樣已建立索引的字段使應用程序可以快速檢索某個元素或屬性值并獲取相應的文件。 舉例來說,假如你有一些符合下列DTD的文件,希望建立作者的索引: <!ELEMENT Brochure (Title, Author, Content)> Authors Brochures SELECT Brochure 6.3 原生XML數據庫 (Native XML Databases) 顯然原生XML數據庫最適于存儲以文檔為中心的文件。這是由于原生XML數據庫保留了文件[元素?]順序、處理指令、注釋、CDATA塊以及實體引用等,而支持XML的數據庫(XML-enabled database)無法做到。此外,原生數據庫支持XML查詢語言,你可以對它提這樣的問題:“找出所有第三段內包含粗體字的文件”,用SQL顯然很難進行這樣的查詢。 原生XML數據庫還適用于存儲那些“天然格式”為XML的文件,而不管這些文件包含什么內容。例如,電子商務系統消息所用的XML文件。盡管這些文件可能是以數據為中心的,而作為消息來說它們的天然格式是XML。這樣當它們被存入消息隊列后,建立在原生XML數據庫上的消息隊列使用起來更為方便。原生XML數據庫保留了XML的特性比如XML查詢語言,通常能更快地取出整條消息。Web cache是這類應用的另一個例子。 原生XML數據庫的其他用途是存儲半結構化數據、在某種特定情形下提高存取速度以及存儲沒有DTD的文件(良構的文件)。前兩種已經在5.3 原生XML數據庫的數據存儲中敘述過。而后一種用非XML的數據庫是做不好的。也就是說,原生XML數據庫無須事先配置即可接受和存儲任何XML文件。將XML文件中的數據轉換到關系型或面向對象型數據庫必須首先建立映射和數據庫模型。無須事先配置對于搜索引擎之類的應用程序來說是有利的,因為沒有任何DTD能適用于所有搜索文檔。 6.3.1 什么是原生數據庫(Native XML Database)? 有一個接近的定義(出自XML:DB mailing list的一個成員)這樣定義原生XML數據庫(native XML database): 它為 XML 文檔(而不是文檔中的數據)定義了一個(邏輯)模型,并根據該模型存取文件。這個模型至少應包括元素、屬性、PCDATA 和文件順序。這種模型的例子有XPath數據模型、XML Infoset 以及 DOM 所用的模型和SAX 1.0的事件。 它以 XML 文件作為其基本(邏輯)存儲單位,正如關系數據庫以表中的行作為基本(邏輯)存儲單位。 定義的第二個部分是說原生數據庫的基本存儲單位是 XML 文件。看起來似乎也可存儲 XML 文件片斷,但幾乎所有的原生 XML 數據庫都是以文件方式存儲的。 (基本存儲單位就是可以容納一份數據的最低級的上下文 (context),相當于關系數據庫中的行。它的存在并不妨礙以更小的數據單位來讀取數據,比如文件片斷或個別元素,同樣也不影響將不同文件中的片斷進行組合。從關系數據庫的術語來講,相當于數據雖然以行的形式存放,并不意味著無法讀取某個字段的值,或從現有的數據行創建新一行數據。) 該定義的第三部分講的是底層的數據存儲格式并不重要。確實如此,正如關系數據庫所使用的物理存儲格式與數據庫是不是關系型之間毫無關系。 6.3.2 原生XML數據庫的結構 (Native XML Database Architectures) 6.3.2.1 基于文本的原生XML數據庫(Text-Based Native XML Databases) 索引對所有基于文本的原生XML數據庫來說都是一樣的,它可以使查詢引擎很方便地跳到XML文件內的任何地方。這就可以大大提高數據庫存取文件或文件片斷的速度。這是因為數據庫只需進行一次檢索、磁頭定位,再假如所讀的文件在磁盤上是連續[存儲]的話,只需一次讀盤就可讀出整個文件或文件片斷。相反,如果像關系數據庫或基于模型的原生XML數據庫那樣,文件由各個部分組合而成,就必須要進行多次查找定位和多次讀盤動作。 從這個意義上講,基于文本的原生XML數據庫與層次結構的數據庫很相似,當存取預先定義好層次的數據的時候,它比關系數據庫更勝一籌。和層次結構的數據庫一樣,當以其他形式比如轉置層次存取數據時,原生XML數據庫也會遇到麻煩。這個問題的嚴重程度尚未可知,很多關系數據庫都使用邏輯指針,使相同復雜度的查詢以相同的速度完成。由此看來這確實是個問題。 6.3.2.2 基于模型的原生XML數據庫 (Model-Based Native XML Databases) (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) 6.3.3.1 文件集 (Document Collections) 作為另一個例子,假設你想把公司的所有產品的說明書存儲在原生XML數據庫中,在這種情形下,你要先定義一個層次結構。比如,為每種產品定義一個集合,并在其中為每種產品說明書的每個章節都指定一個集合。 這些集合是否被允許嵌套取決于所用的數據庫。 6.3.3.2 查詢語言 (Query Languages) 將來大多數原生XML數據庫大概都要支持W3C的XQuery。 6.3.3.3 更新和刪除 (Updates and Deletes) 6.3.3.4 事務、鎖定和并發 (Transactions, Locking, and Concurrency) 例如用戶手冊分成幾個章節,每個章節都是一個文件,這時并發問題就小一些,因為兩個作者同時對同一章節進行更新的情況不大可能發生。而另一方面,如果整個公司的客戶數據都放在同一個文件中(糟糕的設計),文件級的鎖定很容易造成災難性的后果。 將來,大多數的原生數據庫應該會提供文件片斷級的鎖定。 6.3.3.5 應用程序接口 (Application Programming Interfaces ,APIs) 對以數據為中心的應用來說比較有趣的特性是將應用程序變量與返回文檔的特定元素或屬性相關聯的能力。這就免除了應用程序為構件內部數據對象而不得不對文檔進行解析的工作,隨著XML數據綁定技術的應用越來越多,看起來這個特性會得到廣泛支持。 雖然大多數原生XML數據庫都提供有自己的API,但是XML:DB.org已經開發出一種與供應商無關的XML數據庫API (vendor-neutral XML database API),許多原生XML數據庫已經支持它,而且有些非原生的[XML]數據庫也可能支持。不管這個或其他的API是否會成為工業標準,此類API的廣泛采用最終是不可避免的。 大多數原生數據庫還有將查詢結果通過 HTTP 返回的能力。 6.3.3.6 “往返車票”(Round-Tripping) (對于以數據為中心的應用來說,由于它主要關心的是元素、屬性、文本以及層次順序,這種“往返車票”顯得不是很重要。能夠在XML文件和數據庫之間交換數據的軟件都可以處理這些往返問題,如果同級元素的順序對以數據為中心的應用程序來說很重要,在有限幾種情況下也可以保留這種順序。但是由于它[指一般的交換軟件--譯者注]一般不保留兄弟元素的順序,也不確保原樣保持處理指令、注釋以及物理結構(實體引用、CDATA等等),所以不適于以文檔為中心的應用。) 所有原生XML數據庫都能夠在元素、屬性、CDATA和文件順序的級別上為文件提供“往返車票”,至于究竟能達到什么程度取決于數據庫。一般來說,基于文本的原生XML數據庫能夠原樣存取XML文件,而基于模型的原生XML數據庫只能在文件模型的級別上原樣存取XML文件。對于特別小的文檔模型,意味著比普通的XML原樣存取的級別低。 由于你的應用程序要求決定了應當在哪個級別原樣存取,所以對原生XML數據庫的選擇余地可能很大,也可能很小。 6.3.3.7 外部數據 (Remote Data) 6.3.3.8 索引 (Indexes) 6.3.3.9 外部實體存儲 (External Entity Storage) 例如,假設文檔中包含一個外部實體用來調用一個當前天氣報告的CGI程序。如果將這個文件用于提供天氣預報的網頁,那么將這個實體展開就是錯誤的,因為網頁中提供的不是即時的數據。相反,如果文件是氣象歷史資料的一部分,那么不展開它反而是不對的,否則文件總是含有當前的數據而不是歷史資料了。 再看另外一個例子,假設一個產品手冊只包含指向手冊中其他章節的外部實體引用。如果這些章節又被其他文件(比如該產品的另一種型號的手冊)使用,那么展開這些引用就不對了,因為這會造成同一個章節有多份拷貝。 我不知道原生XML數據庫如何處理這個問題。最理想的當然是允許你根據不同情況指定是否展開外部實體引用。 6.3.4 規范化,引用完整性和可伸縮性 (Normalization, Referential Integrity, and Scalability) 6.3.4.1 規范化 (Normalization) 在進一步討論規范性之前,需要指出對許多以文檔為中心的文件這不是大問題。例如有一些描述公司產品信息的文件,通常各個文件的公用數據很少--比如版權聲明、公司地址和電話號碼、產品標志等等,其數量相對來說太小了,幾乎沒有人考慮它的存儲規范性。(但是,其他種類的文檔可能有許多重疊內容,有必要進行規范化)。 與關系型數據庫一樣,原生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) 在關系型數據庫中,引用完整性意味著確保外部鍵指向合法的主鍵,也就是說,對每個外部鍵都要檢查相應的主鍵記錄。在原生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數據庫比關系型數據庫甚至更好,因為可伸縮性與初次索引查找有關,而不是關系型數據庫所用的多次查找。(需要指出,關系型數據庫也以集簇索引(clustered indexes)的形式提供數據的物理鏈接。不過,這種鏈接是應用于各個表格而不是整體層次上的。) 令人遺憾的是這種可伸縮性是有限的。就像層次型數據庫,原生XML數據庫中所用的物理連接只能作用于特定的層次。也就是說,如果數據的讀取和數據的存儲在同一層次下,則讀取速度很快,否則就不一定快。例如將客戶信息存儲在各個銷售訂單文件中,則讀取銷售訂單時的速度很快,而如果需要的數據視圖不同,比如要找出某個客戶的所有訂單將會很慢,因為此時物理連接已不再適用。) 為了緩解這個問題,原生XML數據庫大量使用了索引,經常對所有元素和屬性都作了索引。這雖然有助于減少讀取時間,卻增加了更新時間,因為維護這種索引的代價很高。在只讀的環境下這無關緊要,在交易頻繁的環境下可能造成麻煩。 最后,對于未索引數據的查找來說,原生XML數據庫的可伸縮性比關系型數據庫差的多。此時這兩種數據庫都要線性地查找數據,而原生XML數據庫的情況更為糟糕,因為它的數據不是完全規范的。比如你要查找某個日期的所有銷售訂單,而日期是未經索引的。如果用的是關系型數據庫,就要讀取所有OrderDate字段的值,而對于原生XML數據庫,這意味著要讀取每個銷售訂單文件,并從中查找<OrderDate>元素。不但需要讀取<OrderDate>元素的內容;而且還要讀取所有其它文件的內容。對于基于文本的原生XML數據庫,情況也很不妙:在與目標日期比較之前,必須先對文本進行解析并轉換為日期格式。 那么對你來說,可伸縮性是否嚴重?這完全取決于你的應用。如果你的應用程序中所需的數據一般都和其存儲形式相同,則原生XML數據庫的可伸縮性應是不錯的。許多以文本為中心的應用就屬于這種情形。例如組成產品手冊的文檔幾乎總是作為整體讀取的。反之,如果你的應用中數據視圖不是很確定,則可伸縮性有可能出問題。 對于原生XML數據庫的討論就到此結束。在接下來的兩部分中,我們將考察兩種特殊的原生XML數據庫:可持久化DOM和內容管理系統。 6.3 可持久化DOM (Persistent DOMs, PDOMs) 由于PDOM樹是實時的,數據庫通常是在本地。這就是說,它和應用程序在同一個進程空間,或者至少在同一部機器(盡管這并不是必需的)。這是出于性能上的考慮,因為外部數據庫上的PDOM必須經常向遠程服務器發出請求。 PDOM在DOM應用程序中所起的作用和在面向對象的應用程序中面向對象的數據庫的作用一樣:它為應用程序的數據提供了可持久化的存儲,也可作為應用程序的虛擬內存。后一種作用對于操作大型文件的DOM應用來說有著特殊的重要性,因為DOM與XML文件長度之比很容易超過10。(實際的系數取決于文件中文本的平均長度,文本的平均長度較小的文件其系數較高。) 6.4 內容管理系統 (Content Management Systems) 版本和訪問控制。 7.0 XML 數據庫產品 (Database Products) 8.0 相關鏈接 (Additional Links) 9.0 意見和反饋 (Comments and Feedback) 感謝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 及其他人的意見和耐心。 |
|
來自: Ralf_Jones > 《其它》