本文探討 sql server 2005 中內(nèi)置的 xml 支持。描述了這種支持如何與 .net 框架 v2.0 和本機(jī)代碼(例如 oledb 和 sqlxml)均支持的客戶端編程相集成。
一、簡介
可擴(kuò)展標(biāo)記語言 (xml) 作為一種與平臺無關(guān)的數(shù)據(jù)表示形式已被廣泛采用。它對于在松散耦合且完全不同的系統(tǒng),以及各種企業(yè)到企業(yè) (b2b) 應(yīng)用和工作流范疇內(nèi)交換信息是很有用的。數(shù)據(jù)交換已成為 xml 技術(shù)的主要驅(qū)動(dòng)力之一。.
xml 在企業(yè)應(yīng)用程序中的使用正日益廣泛,它主要用于對半結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)進(jìn)行建模。文檔管理就是這樣的一種應(yīng)用程序。像電子郵件這樣的文檔是半結(jié)構(gòu)化性質(zhì)的。如果文檔以 xml 的形式存儲在數(shù)據(jù)庫服務(wù)器中,就可以開發(fā)功能強(qiáng)大的應(yīng)用程序來根據(jù)文檔內(nèi)容檢索文檔、查詢部分內(nèi)容(例如查找標(biāo)題包含單詞“背景”的部分),以及查詢文檔聚合。如果存在能夠生成和使用 xml 的應(yīng)用程序,則這樣的方案就變得可行了。例如,microsoft office 2003 系統(tǒng)允許用戶以 xml 標(biāo)記的形式生成 word、excel、visio 和 infopath 文檔。
為什么使用關(guān)系數(shù)據(jù)庫來存儲 xml 數(shù)據(jù)?| • | 將 xml 數(shù)據(jù)存儲在關(guān)系數(shù)據(jù)庫中會給數(shù)據(jù)管理和查詢處理帶來好處。sql server 提供了強(qiáng)大的查詢和修改關(guān)系數(shù)據(jù)的能力,而且已經(jīng)擴(kuò)展到查詢和修改 xml 數(shù)據(jù)。這使得可以利用在過去的版本上所進(jìn)行的投資,就如同基于成本的優(yōu)化和數(shù)據(jù)存儲領(lǐng)域一樣。例如,關(guān)系數(shù)據(jù)庫中的索引技術(shù)已經(jīng)廣為人知,而且已經(jīng)擴(kuò)展到用于索引 xml 數(shù)據(jù),這樣就可以使用基于成本的決策來優(yōu)化查詢。 | 
| • | xml 數(shù)據(jù)可以與現(xiàn)有的關(guān)系數(shù)據(jù)和 sql 應(yīng)用程序進(jìn)行互操作,這樣就可以在需要進(jìn)行數(shù)據(jù)建模而又不破壞現(xiàn)有的應(yīng)用程序的系統(tǒng)中引入 xml。數(shù)據(jù)庫服務(wù)器還提供了管理功能來管理 xml 數(shù)據(jù)(例如備份、恢復(fù)和復(fù)制)。 | 
| • | 這些功能促進(jìn)了對 sql server 2005 中的原生 xml 支持的需求,從而解決了不斷增加的 xml 使用的問題。sql server 2005 中的 xml 支持將給企業(yè)應(yīng)用程序開發(fā)帶來好處。 | 
| • | 下面幾部分將概述 sql server 2000 和 2005 中的 xml 支持,描述一些推動(dòng) xml 使用的方案,并且詳細(xì)討論服務(wù)器端和客戶端的 xml 功能集。 | 
這一部分簡要概述了 sql server 2000 中的 xml 支持,以及隨后發(fā)布的 sqlxml 客戶端編程平臺 web 版,它提供了豐富的支持來將關(guān)系數(shù)據(jù)映射到 xml 數(shù)據(jù)或?qū)?xml 數(shù)據(jù)映射到關(guān)系數(shù)據(jù)。
服務(wù)器端支持在服務(wù)器上,xml 數(shù)據(jù)可以從表生成,并通過在 select 語句中使用 for xml 子句來查詢結(jié)果。這對于數(shù)據(jù)交換和 web 服務(wù)應(yīng)用程序是很理想的。for xml 的逆函數(shù)是一個(gè)名為 openxml 的關(guān)系行集合生成器函數(shù);它通過求 xpath 1.0 表達(dá)式的值來從 xml 數(shù)據(jù)提取值,并將其放到行集合的列中。應(yīng)用程序使用 openxml 來“切碎”傳入 xml 數(shù)據(jù),并將其存放到表中,或者用于通過 t-sql 語言進(jìn)行的查詢。
客戶端支持sql server 2000 對客戶端編程的支持稱為 sqlxml。這項(xiàng)技術(shù)的核心是 xml 視圖,它是 xml 架構(gòu)和關(guān)系表之間的雙向映射。sql server 2000 只支持 xdr 架構(gòu)的映射,盡管在后續(xù)的 web 版中增加了對 xsd 的支持。xml 視圖允許使用 xpath 1.0 的一個(gè)子集來進(jìn)行查詢,其中,可以使用映射將路徑表達(dá)式轉(zhuǎn)換成底層表中的 sql 查詢,并且將查詢結(jié)果打包成 xml 結(jié)果。
sqlxml 還支持您創(chuàng)建 xml 模板,這使得您可以創(chuàng)建帶有動(dòng)態(tài)部分的 xml 文檔。在 xml 文檔中,您可以嵌入 for xml 查詢和/或映射查詢之上的 xpath 1.0 表達(dá)式。在執(zhí)行 xml 模板時(shí),可以用查詢的結(jié)果來替換查詢塊。通過這種方式,您可以創(chuàng)建帶有某些靜態(tài)內(nèi)容和某些數(shù)據(jù)驅(qū)動(dòng)的動(dòng)態(tài)內(nèi)容的 xml 文檔。
在sql server 2000 中,有兩種訪問 sqlxml 功能的主要方法:
| • | sqlxmloledb provider。sqlxmloledb provider 是一個(gè) ole db 提供程序,它通過 ado 公開 microsoft sqlxml 功能。 | 
| • | http 訪問。sql server 2000 中的 sqlxml 功能也可以使用 sqlxml isapi 過濾器通過 http 進(jìn)行訪問。通過使用我們的配置工具,您可以建立網(wǎng)站來檢索傳入請求,從而通過 http 執(zhí)行 xml 模板、xml 視圖之上的 for xml 和 xpath 1.0 語句。 | 
服務(wù)器和客戶端編程平臺為基于表格和 xml 數(shù)據(jù)之間的映射生成和使用 xml 數(shù)據(jù)提供了豐富的支持。這能夠相當(dāng)好地處理結(jié)構(gòu)化 xml 數(shù)據(jù)。在 sqlxml 中,查詢語言是 xpath 1.0 的一個(gè)子集,并且有一些局限性。例如,不支持 descendant-or-self 軸 (//)。因此,在開發(fā)某些解決方案時(shí)會存在一定的限制。例如,不保存 xml 文檔順序,而這對于像文檔管理這樣的應(yīng)用程序來說是非常關(guān)鍵的。此外,還不支持遞歸的 xml 架構(gòu)。盡管存在這樣一些局限性,但是客戶端 sqlxml 和服務(wù)器 xml 功能還是在應(yīng)用程序開發(fā)中得到了廣泛的使用。sql server 2005 解決了許多這樣的限制,擴(kuò)展了關(guān)系 xml 交換功能,并且還提供了原生 xml 支持。
sql server 2005 中的 xml 支持概述這一部分簡要概述了 sql server 2005 中增加的新的 xml 支持,它是通過.net 框架 v2.0 中的支持和本機(jī)客戶端數(shù)據(jù)訪問(如 ole db)進(jìn)行補(bǔ)充的。
xml 數(shù)據(jù)類型xml 數(shù)據(jù)模型具有一些特性,這些特性使得映射到關(guān)系數(shù)據(jù)模型非常困難,如果不是完全不可能的話。xml 數(shù)據(jù)具有可以遞歸的層次結(jié)構(gòu);關(guān)系數(shù)據(jù)庫提供對層次數(shù)據(jù)(建模為外鍵關(guān)系)的弱支持。文檔順序是 xml 實(shí)例的固有屬性,并且必須保存在查詢結(jié)果中。這與關(guān)系數(shù)據(jù)形成了對比,關(guān)系數(shù)據(jù)是無序的,必須通過附加的排序列來強(qiáng)制進(jìn)行排序。在查詢時(shí)重新組合結(jié)果是很費(fèi)力的,因?yàn)閷?shí)際的 xml 架構(gòu)將 xml 數(shù)據(jù)分解到大量的表中。
sql server 2005 引入了一種稱為 xml 的本機(jī)數(shù)據(jù)類型。用戶可以創(chuàng)建這樣的表,它在關(guān)系列之外還有一個(gè)或多個(gè) xml 類型的列;此外,還允許帶有變量和參數(shù)。為了更好地支持 xml 模型特征(例如文檔順序和遞歸結(jié)構(gòu)),xml 值以內(nèi)部格式存儲為大型二進(jìn)制對象 (blob)。
sql server 2005 提供了 xml 架構(gòu)集合,可以將其作為一種方法來以元數(shù)據(jù)的形式管理 w3c xml 架構(gòu)。xml 數(shù)據(jù)類型可以與 xml 架構(gòu)集合相關(guān)聯(lián),以便對 xml 實(shí)例強(qiáng)加架構(gòu)限制。當(dāng) xml 數(shù)據(jù)與 xml 架構(gòu)集合相關(guān)聯(lián)時(shí),它稱為類型化的 xml;否則,就稱為非類型化的 xml。在一個(gè)框架中可以同時(shí)容納類型化的 xml 和非類型化的 xml,保留 xml 數(shù)據(jù)模型,并且強(qiáng)制采用 xml 語義進(jìn)行查詢處理。底層關(guān)系基礎(chǔ)結(jié)構(gòu)被廣泛用于這一目的。它支持關(guān)系數(shù)據(jù)和 xml 數(shù)據(jù)之間的互操作,這為更廣泛地采用 xml 功能開辟了道路。
xml 數(shù)據(jù)類型查詢和數(shù)據(jù)修改可以使用 t-sql select 語句來檢索 xml 實(shí)例。在 xml 數(shù)據(jù)類型中提供了五種內(nèi)置的方法來查詢和修改 xml 實(shí)例。
xml 數(shù)據(jù)類型的方法接受 xquery,它是一種新出現(xiàn)的 w3c 標(biāo)準(zhǔn)語言(目前處于 last call(最后請求)狀態(tài)),并且包括導(dǎo)航語言 xpath 2.0。也可以使用一種語言來修改 xml 數(shù)據(jù),比如添加或刪除子樹和更新標(biāo)量值。與一大組函數(shù)一起,嵌入式的 xquery 和數(shù)據(jù)修改語言為處理 xml 數(shù)據(jù)提供了豐富的支持。
xquery 類型系統(tǒng)與 w3c xml 架構(gòu)類型是一致的。大多數(shù) sql 類型與 xquery 類型系統(tǒng)是兼容的(例如,小數(shù))。少數(shù)類型(例如,xs:duration)是以內(nèi)部格式存儲的,并且可以通過適當(dāng)?shù)慕忉寔砼c xquery 類型系統(tǒng)兼容。
編譯階段檢查 xquery 表達(dá)式和數(shù)據(jù)修改語句的靜態(tài)類型的正確性,并且在類型化 xml 的情況下使用 xml 架構(gòu)來進(jìn)行類型推理。如果表達(dá)式由于類型安全沖突而在運(yùn)行時(shí)失敗,則會產(chǎn)生靜態(tài)類型錯(cuò)誤。
xml 索引查詢執(zhí)行在運(yùn)行時(shí)處理每個(gè) xml 實(shí)例;如果 xml 值比較大或需要在表的許多行中對查詢進(jìn)行求值,則查詢執(zhí)行就會變得非常費(fèi)時(shí)。因此提供了一種索引 xml 列的機(jī)制來加速查詢。
b+ 樹廣泛用于建立關(guān)系數(shù)據(jù)的索引。xml 列的主 xml 索引在該列中 xml 實(shí)例的所有標(biāo)記、值和路徑上都創(chuàng)建一個(gè) b+ 樹索引。通過這種方式,可以有效地對 xml 數(shù)據(jù)中的查詢進(jìn)行求值,并且在保留文檔順序和文檔結(jié)構(gòu)的同時(shí)從 b+ 樹重新組合 xml 結(jié)果。
可以在 xml 列中創(chuàng)建次 xml 索引來加速不同類別的常見查詢:path 索引(用于基于路徑的查詢)、property 索引(用于屬性包的情況)和 value 索引(用于基于值的查詢)。
xml 架構(gòu)處理xml 列、變量和參數(shù)可以根據(jù) xml 架構(gòu)的集合(它可能與另一個(gè)集合相關(guān)(例如,通過使用 )或不相關(guān))有選擇地進(jìn)行類型化。每個(gè)類型化的 xml 實(shí)例都從它遵循的 xml 架構(gòu)集合指定目標(biāo)命名空間。數(shù)據(jù)庫引擎在數(shù)據(jù)分配和修改時(shí)根據(jù) xml 架構(gòu)來驗(yàn)證實(shí)例的有效性。
xml 架構(gòu)信息用于存儲和查詢優(yōu)化。類型化的 xml 實(shí)例在內(nèi)部的二進(jìn)制表示中包含類型化的值,這與 xml 索引中的一樣。通過這種方式,可以有效地處理類型化 xml 數(shù)據(jù)。
關(guān)系數(shù)據(jù)和 xml 數(shù)據(jù)的集成用戶可以在同一個(gè)數(shù)據(jù)庫中存儲關(guān)系數(shù)據(jù)和 xml 數(shù)據(jù)。簡而言之,數(shù)據(jù)庫引擎除了知道如何遵循關(guān)系數(shù)據(jù)模型之外,還知道如何遵循 xml 數(shù)據(jù)模型。在升級到 sql server 2005 之后,關(guān)系數(shù)據(jù)和 sql 應(yīng)用程序仍然能夠正常工作。在服務(wù)器上,可以將駐留在文件和文本或圖像列中的 xml 數(shù)據(jù)移到 xml 數(shù)據(jù)類型的列中。通過使用 xml 數(shù)據(jù)類型的方法,可以建立 xml 列的索引,并對其進(jìn)行查詢和修改。
數(shù)據(jù)庫利用現(xiàn)有的關(guān)系基礎(chǔ)結(jié)構(gòu)和引擎組件(例如存儲引擎和查詢處理器)來進(jìn)行 xml 處理。例如,xml 索引可以創(chuàng)建 b+ 樹,而且可以在 showplan 輸出中查看查詢計(jì)劃。通過集成到關(guān)系框架中,數(shù)據(jù)管理功能(如備份/恢復(fù)和復(fù)制)可用于 xml 數(shù)據(jù)。同樣地,新的數(shù)據(jù)管理功能(如數(shù)據(jù)庫鏡像和快照隔離)可以處理 xml 數(shù)據(jù)類型,以提供無縫的用戶體驗(yàn)。
結(jié)構(gòu)化數(shù)據(jù)應(yīng)該存儲在表和關(guān)系列中。當(dāng)應(yīng)用程序需要執(zhí)行細(xì)粒度查詢和數(shù)據(jù)修改時(shí),對于使用 xml 的半結(jié)構(gòu)化數(shù)據(jù)和標(biāo)記數(shù)據(jù),xml 數(shù)據(jù)類型是比較合適的選擇。
for xml 和 openxml 增強(qiáng)現(xiàn)有的 for xml 功能已經(jīng)在幾個(gè)方面得到了增強(qiáng)。它能夠處理 xml 數(shù)據(jù)類型的實(shí)例和其他新的 sql 類型,例如 [n]varchar(max)。
新的 type 指令生成的 xml 數(shù)據(jù)類型實(shí)例可以分配給 xml 列、變量或參數(shù),也可以使用 xml 數(shù)據(jù)類型的方法進(jìn)行查詢。這允許嵌套 select ...for xml type 語句。
path 模式允許用戶指定出現(xiàn)列值的 xml 樹中的路徑,并且與上述嵌套一起使用時(shí)比 for xml explicit 更易于編寫。
xsinil 指令與 elements 一起使用,可以將 null 映射到帶有屬性 xsi:nil="true" 的元素。另外,新的 root 指令還允許在所有的 for xml 模式下指定根節(jié)點(diǎn)。新的 xmlschema 指令生成 xsd 內(nèi)聯(lián)架構(gòu)。
openxml 的功能增強(qiáng)包括在 sp_preparedocument 中接受 xml 數(shù)據(jù)類型以及在行集中生成 xml 和新的 sql 類型的列。
對 xml 數(shù)據(jù)類型的客戶端訪問客戶端可以通過幾種方式訪問服務(wù)器中的 xml 數(shù)據(jù)。使用 odbc 和 ole db 的本機(jī) sql 客戶端訪問以 unicode 字符串的形式傳遞 xml 數(shù)據(jù)類型。ole db 還提供對流 unicode 數(shù)據(jù)的 xml 數(shù)據(jù)類型的 isequentialstream 訪問。
托管訪問通過 .net 框架 v2.0 中的 ado.net 將 xml 數(shù)據(jù)作為一個(gè)名為 sqlxml 的新類進(jìn)行傳遞。它支持一個(gè)名為 createreader() 的方法,該方法返回 xmlreader 實(shí)例來讀取返回的 xml。同樣地,數(shù)據(jù)集能夠?qū)?xml 數(shù)據(jù)類型的實(shí)例加載到中間層的列,中間層可以作為 xml 文檔進(jìn)行編輯,并且重新保存到 sql server。這兩者都支持對服務(wù)器發(fā)出 sql 查詢,以檢索在中間層操作的 xml 列。
在 sql server 2005 中,可以使用直接對 http 終結(jié)點(diǎn)進(jìn)行的soap 訪問來查詢、檢索和修改 xml 數(shù)據(jù)。
本機(jī)和托管客戶端技術(shù)都提供了新的接口來檢索類型化 xml 列的 xml 架構(gòu)集合。
帶有 xquery 的客戶端 xml 支持除了使用 ado.net 來檢索表并將結(jié)果存放到關(guān)系數(shù)據(jù)集中之外,您還可以使用 xquerycommand 類將關(guān)系數(shù)據(jù)直接加載到中間層的 xml 文檔。該類提供了一個(gè)中間層 xquery 處理器,它能夠?qū)?t-sql 語句作為 xquery 語言的一部分嵌入。通過這種方式,您可以查詢本地 xml 文件,也可以從 sql server 檢索數(shù)據(jù)(直接從表或者通過數(shù)據(jù)庫存儲程序),再將數(shù)據(jù)構(gòu)造成 xml 格式,然后將其加載到中間層 xml 文檔。這大大簡化了 sql server 中的查詢,將查詢結(jié)果構(gòu)造成特定的 xml 格式,并使其流向業(yè)務(wù)合作伙伴,而不需要將數(shù)據(jù)加載到數(shù)據(jù)集來執(zhí)行數(shù)據(jù)轉(zhuǎn)換。
二、推動(dòng) xml 存儲方案
xml 數(shù)據(jù)變得越來越普遍.它可以表示客戶數(shù)據(jù),帶有或不帶有描述數(shù)據(jù)的 xml 架構(gòu)均可。xml 數(shù)據(jù)和 xml 架構(gòu)需要在一起進(jìn)行管理。實(shí)際應(yīng)用程序的 xml 架構(gòu)通常比較復(fù)雜,因而將這樣的 xml 架構(gòu)映射到表和列是一項(xiàng)復(fù)雜的任務(wù)。當(dāng) xml 架構(gòu)改變或新的架構(gòu)加入系統(tǒng)時(shí),長時(shí)間維護(hù)這樣的映射是一件很麻煩的事情。通常,xml 數(shù)據(jù)存儲在文件系統(tǒng)或數(shù)據(jù)庫服務(wù)器的文本列中。文本列有數(shù)據(jù)管理方面的好處(例如,復(fù)制和備份/恢復(fù)),但是不提供任何基于數(shù)據(jù)的 xml 結(jié)構(gòu)的查詢支持。在具有原生 xml 支持的情況下,使用 xml 進(jìn)行應(yīng)用程序開發(fā)變得更快。
自定義屬性管理一些應(yīng)用程序(例如用戶界面軟件)允許用戶從一組固定的屬性中進(jìn)行選擇。而其他應(yīng)用程序則允許用戶定義他們自己感興趣的屬性。如果這樣的自定義屬性是以 xml 的格式存儲的,它們就可以很好地進(jìn)行管理。應(yīng)用程序可以支持標(biāo)量屬性以外的屬性:
| • | 可以支持對象中的多值屬性,例如,多個(gè)電話號碼。 | 
| • | 可以支持復(fù)雜屬性,例如,一個(gè)文檔的作者屬性可能是該作者的聯(lián)系信息。 | 
可以將對象屬性存儲在 xml 數(shù)據(jù)類型的列中并建立索引,從而提高查詢處理的效率。
數(shù)據(jù)交換和工作流xml 允許采用平臺無關(guān)的方式在應(yīng)用程序之間交換數(shù)據(jù)。可以使用 xml 標(biāo)記將這樣的數(shù)據(jù)建模為消息。代替不斷地分割和生成 xml 消息,以 xml 的格式存儲消息是明智的。這正是數(shù)據(jù)流所需要的。到達(dá)工作流階段的 xml 消息攜帶著當(dāng)前的狀態(tài)。每個(gè)消息都需要進(jìn)行處理,處理的進(jìn)展記錄在 xml 內(nèi)容中(如狀態(tài)改變),然后將 xml 數(shù)據(jù)轉(zhuǎn)發(fā)到工作流處理的下一個(gè)階段。消息可能是不同類型的,甚至可能是半結(jié)構(gòu)化的,并且有不同的 xml 架構(gòu)與它們相關(guān)聯(lián),因此將它們映射到表并不總是一件輕而易舉的事。
針對不同垂直領(lǐng)域(如金融數(shù)據(jù)和地理空間數(shù)據(jù))的基于 xml 的標(biāo)準(zhǔn)正在形成。這些標(biāo)準(zhǔn)根據(jù)可以查詢和更新的實(shí)例數(shù)據(jù)來描述數(shù)據(jù)的結(jié)構(gòu)。通常,實(shí)際數(shù)據(jù)采用的是二進(jìn)制形式,而 xml 數(shù)據(jù)提供關(guān)于它們的元數(shù)據(jù)信息。
舉一個(gè)簡單的例子,為了將一個(gè)輸入?yún)?shù)表傳送到存儲程序或函數(shù),應(yīng)用程序首先將數(shù)據(jù)轉(zhuǎn)換成 xml,然后將其作為一個(gè) xml 數(shù)據(jù)類型參數(shù)進(jìn)行傳遞。在存儲過程或函數(shù)內(nèi),從 xml 參數(shù)重新生成行集。
文檔管理假設(shè)有一個(gè)呼叫中心,它采用 xml 文檔來維護(hù)患者記錄和談話。當(dāng)患者發(fā)起呼叫時(shí),呼叫中心希望恢復(fù)前面的談話以設(shè)置傳入呼叫的情景。這可以通過查詢 xml 標(biāo)記實(shí)現(xiàn),從而給應(yīng)用程序帶來好處。此外,還可以方便地檢索以前談話的細(xì)節(jié)并記錄當(dāng)前的談話。
像電子郵件之類的文檔本質(zhì)上是半結(jié)構(gòu)化的。帶有 xml 標(biāo)記的文檔正變得越來越容易創(chuàng)建,例如,使用 office 2003。可以將這些 xml 文檔存儲在 xml 列中,并建立索引,進(jìn)行查詢和更新。因此,通過利用原生 xml 支持,開發(fā)人員可以做更多的事情。
三、sql server 2005 中的服務(wù)器端 xml 處理
sql server 2005 支持包括提供一個(gè)數(shù)據(jù)庫,在這個(gè)數(shù)據(jù)庫中,您可以存儲關(guān)系數(shù)據(jù)和 xml 數(shù)據(jù)。
xml 數(shù)據(jù)類型您可以使用普通的 create table 語句來創(chuàng)建帶有 xml 列的表。然后就可以采用一種特別的方式來建立 xml 的索引。
非類型化的 xmlsql server 2005 xml 數(shù)據(jù)類型實(shí)現(xiàn)了 iso sql-2003 標(biāo)準(zhǔn) xml 數(shù)據(jù)類型。因此,它不僅可以存儲格式良好的 xml 1.0 文檔,而且可以存儲所謂的 xml 內(nèi)容片段(帶有文本節(jié)點(diǎn)和任意數(shù)目的頂層元素)。在對數(shù)據(jù)進(jìn)行格式良好性檢查時(shí),并不要求將 xml 數(shù)據(jù)類型綁定到 xml 架構(gòu),但是格式不規(guī)范的數(shù)據(jù)將被拒絕。
當(dāng)架構(gòu)不是已知先驗(yàn)的 并且因此而導(dǎo)致基于映射的解決方案不可能實(shí)現(xiàn)時(shí),就可以使用非類型化的 xml。如果架構(gòu)是已知的,但映射到關(guān)系數(shù)據(jù)模型非常復(fù)雜并且難于維護(hù),或者存在多個(gè)架構(gòu)而且這些架構(gòu)是后來根據(jù)外部要求綁定到數(shù)據(jù)的,也可以使用非類型化的 xml。
例:表中非類型化的 xml 列
下面的語句創(chuàng)建一個(gè)名為“docs”的表,該表帶有整型主鍵“pk”和非類型化的 xml 列“xcol”:
create table docs (pk int primary key, xcol xml not null)也可以創(chuàng)建一個(gè)包含多個(gè) xml 列或關(guān)系列、帶主鍵或不帶主鍵的表。
類型化的 xml如果 xml 架構(gòu)集合中有描述 xml 數(shù)據(jù)的 xml 架構(gòu),就可以將 xml 架構(gòu)集合與產(chǎn)生類型化 xml 的 xml 列相關(guān)聯(lián)。可以使用 xml 架構(gòu)來驗(yàn)證數(shù)據(jù)的有效性,在編譯查詢和數(shù)據(jù)修改語句時(shí)執(zhí)行比非類型化的 xml 更精確的類型檢查,以及優(yōu)化存儲和查詢處理。
類型化的 xml 列、參數(shù)和變量可以存儲 xml 文檔或內(nèi)容,可以在聲明時(shí)將其指定為一個(gè)選項(xiàng)(分別為document 或 content,默認(rèn)為 content)。此外,還必須提供 xml 架構(gòu)集合。如果每個(gè) xml 實(shí)例都正好有一個(gè)頂層元素,則指定 document;否則,使用 content。查詢編譯器在類型檢查中使用 document 標(biāo)記來推理 singleton 頂層元素。
例:表中的類型化 xml 列
xml 列、變量和參數(shù)可以綁定到一個(gè) xml 架構(gòu)集合(請參閱本文后面的“xml 架構(gòu)處理”一節(jié)以獲得更多的詳細(xì)信息和示例)。假定 mycollection 代表這樣一個(gè)集合。下面的語句創(chuàng)建一個(gè)表 xmlcatalog,帶有使用 mycollection 進(jìn)行類型化的 xml 列文檔。類型化的 xml 列還被指定為接受 xml 片段,而不只是 xml 文檔。
create table xmlcatalog (
  id int primary key,
  document xml(content mycollection))約束 xml 數(shù)據(jù)類型的列 | • | 除了類型化一個(gè) xml 列之外,還可以在類型化和非類型化的 xml 數(shù)據(jù)類型的列中使用關(guān)系(列或行)約束。大部分 sql 約束同樣可應(yīng)用于 xml 列,值得注意的唯一例外是主鍵和外鍵約束,因?yàn)?xml 數(shù)據(jù)類型的實(shí)例是不兼容的。因此,可以指定 xml 列可為空或不可為空,提供默認(rèn)值,并且在列中定義 check 約束。例如,非類型化的 xml 列可以有 check 約束來驗(yàn)證存儲的 xml 實(shí)例是否符合 xml 架構(gòu)。 | 
在下列條件下使用約束:
| • | 業(yè)務(wù)規(guī)則不能用 xml 架構(gòu)表示。例如,花店的交付地址必須在其業(yè)務(wù)場所 50 英里的范圍內(nèi),這可以編寫成 xml 列中的一個(gè)約束條件。該約束條件可以包括 xml 數(shù)據(jù)類型的方法。 | 
| • | 約束條件涉及表中其他的 xml 或 非 xml 列。這樣的一個(gè)例子就是,使 xml 實(shí)例中存在的 customer (/customer/@custid) 的id 與整型 customerid 列中的值相匹配。 | 
例:約束 xml 列
要確定<book>的<author>的<last-name> 不同于<author>的<first-name> ,可以指定下列 check 約束:
create table docs (pk int primary key, xcol xml not nullconstraint ck_name check (xcol.exist('/book/author[first-name = last-name]') = 0))
文本編碼sql server 2005 將 xml 數(shù)據(jù)存儲為 unicode (utf-16)。從服務(wù)器檢索的xml 數(shù)據(jù),其結(jié)果也是 utf-16 編碼的。如果想要采用一種不同的編碼方式,就需要在檢索數(shù)據(jù)之后進(jìn)行必要的轉(zhuǎn)換,轉(zhuǎn)換的方法有兩種,一種是通過強(qiáng)制類型轉(zhuǎn)換,另一種是在中間層執(zhí)行轉(zhuǎn)換。例如,可以在服務(wù)器上將 xml 數(shù)據(jù)強(qiáng)制轉(zhuǎn)換成 varchar 類型,在這種情況下,數(shù)據(jù)庫引擎會通過 varchar 類型的排序所確定的編碼方式來序列化 xml。
存儲 xml 數(shù)據(jù)可以通過多種方式為 xml 列、參數(shù)或變量提供 xml 值。
| • | 作為隱式轉(zhuǎn)換到 xml 數(shù)據(jù)類型的字符或二進(jìn)制 sql 類型。 | 
| • | 作為文件的內(nèi)容。 | 
| • | 作為 xml 發(fā)布機(jī)制 for xml 的輸出(帶有生成 xml 數(shù)據(jù)類型實(shí)例的 type 指令) | 
對提供的值進(jìn)行格式良好性檢查,并且允許存儲 xml 文檔和 xml 片段。如果數(shù)據(jù)沒有通過格式良好性檢查,則拒絕它,并發(fā)出一個(gè)適當(dāng)?shù)腻e(cuò)誤消息。
對于類型化的 xml,需要檢查提供的值是否符合已注冊到類型化 xml 列的 xml 架構(gòu)集合的 xml 架構(gòu)。如果該 xml 實(shí)例沒有通過這種有效性驗(yàn)證,則拒絕它。此外,僅當(dāng) content 允許提供 xml 文檔和內(nèi)容時(shí),類型化的 xml 中的 document 標(biāo)記才將所接受的值限制為 xml 文檔。
例:將數(shù)據(jù)插入非類型化的 xml 列
下列語句在表 docs 中新插入一行,其中在整型的 pk 列插入的值為 1,而在 xml 列插入的是 實(shí)例。 數(shù)據(jù)(作為字符串提供)被隱式地轉(zhuǎn)換為 xml 數(shù)據(jù)類型,并且在插入的過程中進(jìn)行格式良好性檢查。
insert into docs values (1,
'<book genre="security" publicationdate="2002" isbn="0-7356-1588-2">
  <title>writing secure code</title>
  <author>
   <first-name>michael</first-name>
   <last-name>howard</last-name>
  </author>
  <author>
   <first-name>david</first-name>
   <last-name>leblanc</last-name>
  </author>
  <price>39.99</price>
</book>')例:將來自文件的數(shù)據(jù)插入非類型化的 xml 列
如下所示的 insert 語句使用 openrowset 讀取文件 c: empxmlfile.xml 的內(nèi)容作為 blob。在表 docs 中新插入一行,值 10 作為主鍵,而 blob 作為 xml 列 xcol。格式良好性檢查出現(xiàn)在文件內(nèi)容分配到 xml 列時(shí)。
insert into docs
select 10, xcol
from  (select * from openrowset
   (bulk 'c: empxmlfile.xml',
   single_blob) as xcol) as r(xcol)例:將數(shù)據(jù)插入類型化的 xml 列
類型化的 xml 列需要 xml 實(shí)例數(shù)據(jù)指定用于對其進(jìn)行類型化的 xml 架構(gòu)的目標(biāo)命名空間(該命名空間可以為空)。在下面的示例中,這是通過命名空間聲明 xmlns=http://mydvd 來實(shí)現(xiàn)的。
insert xmlcatalog values(2,
'<?xml version="1.0"?>
<dvdstore xmlns="http://mydvd">
 <dvd genre="comedy" releasedate="2003">
  <title>my big fat greek wedding</title>
  <price>19.99</price>
 </dvd>
</dvdstore>')例:存儲使用帶有 type 指令的 for xml 生成的 xml 數(shù)據(jù)
通過 type 指令增強(qiáng)的 for xml 可以生成像 xml 數(shù)據(jù)類型實(shí)例這樣的結(jié)果。結(jié)果 xml 可以分配到 xml 列、變量或參數(shù)。在下面的語句中,使用 for xml type 生成的 xml 實(shí)例被分配給 xml 數(shù)據(jù)類型的變量 @xvar。可以使用 xml 數(shù)據(jù)類型的方法來查詢變量。
declare @xvar xml
set   @xvar = (select * from docs for xml auto,type)
存儲表示
xml 數(shù)據(jù)類型的實(shí)例存儲在內(nèi)部的二進(jìn)制表示中,該表示是可流化的,并且經(jīng)過了優(yōu)化,從而可以更有效地進(jìn)行解析。標(biāo)記映射到整型值,而映射的值存儲在內(nèi)部表示中。這也產(chǎn)生了一些數(shù)據(jù)的壓縮。
對于非類型化的 xml,節(jié)點(diǎn)值存儲為 unicode (utf-16) 字符串,因此需要進(jìn)行運(yùn)行時(shí)類型轉(zhuǎn)換才能執(zhí)行操作。例如,為了求謂詞 /book/price > 9.99 的值,必須將該書的價(jià)格值轉(zhuǎn)換為小數(shù)。而對于類型化的 xml,值的編碼類型為在 xml 架構(gòu)中指定的類型。這使得數(shù)據(jù)的解析更加有效,并且還不必進(jìn)行運(yùn)行時(shí)轉(zhuǎn)換。
存儲的二進(jìn)制形式被限制為每 xml 實(shí)例 2 gb,這可以適應(yīng)大部分的 xml 數(shù)據(jù)。此外,xml 層次的深度還被限制為 128 層。
xml 數(shù)據(jù)的信息集內(nèi)容被保留。但是,它不可能是與文本 xml 一模一樣的副本,因?yàn)橄铝行畔]有保留:無關(guān)緊要的空白、屬性的順序、命名空間前綴和 xml 聲明。
數(shù)據(jù)建模考慮事項(xiàng)
通常,關(guān)系數(shù)據(jù)類型和 xml 數(shù)據(jù)類型的列的組合比較適合數(shù)據(jù)建模。可以將 xml 數(shù)據(jù)中的一些值存儲在關(guān)系列中,而將其余的值或全部的 xml 值存儲在 xml 列中。這可以產(chǎn)生更好的性能和鎖定特性。
對于 singleton 值(即單值屬性),xml 數(shù)據(jù)中的值可以提升為同一個(gè)表中的計(jì)算列。多值屬性需要單獨(dú)的屬性表,該表必須使用觸發(fā)器進(jìn)行填充和維護(hù)。查詢需要直接針對屬性表進(jìn)行編寫。
對于鎖定和更新特性,存儲在 xml 列中的 xml 數(shù)據(jù)的粒度是至關(guān)重要的。sql server 將相同的鎖定機(jī)制用于 xml 和非 xml 數(shù)據(jù)。如果粒度比較大,則在多用戶的情況下,為了更新而鎖定大的 xml 實(shí)例會引起吞吐量的下降。而另一方面,嚴(yán)格的分解會失去對象的封裝性并增加重新組合的成本。
查詢和修改 xml 數(shù)據(jù)
查詢存儲在 xml 列中的 xml 實(shí)例需要解析列中的二進(jìn)制 xml 數(shù)據(jù)。與解析文本形式的 xml 數(shù)據(jù)相比,解析二進(jìn)制的 xml 要快得多。xml 索引避免了重新解析,這將在“建立 xml 數(shù)據(jù)的索引”一節(jié)中進(jìn)行討論。
xml 數(shù)據(jù)類型中的方法
如果感興趣,可以檢索全部 xml 值,也可以檢索部分 xml 實(shí)例。這可以使用四個(gè) xml 數(shù)據(jù)類型的方法來實(shí)現(xiàn):query()、value()、exist() 和 nodes(),它們接受 xquery 表達(dá)式作為參數(shù)。第五個(gè)方法 modify() 允許修改 xml 數(shù)據(jù)并接受 xml 數(shù)據(jù)修改語句作為輸入。
query() 方法用于提取 xml 實(shí)例的部分。xquery 表達(dá)式求值為一個(gè) xml 節(jié)點(diǎn)列表。以這些節(jié)點(diǎn)中的每一個(gè)為根的子樹按照文檔順序返回。結(jié)果類型為非類型化的 xml。
value() 方法從 xml 實(shí)例提取標(biāo)量值。它返回 xquery 表達(dá)式所求值的節(jié)點(diǎn)的值。該值被轉(zhuǎn)換為 value() 方法的第二個(gè)參數(shù)所指定的 t-sql 類型。
exist() 方法用于對 xml 實(shí)例進(jìn)行存在性檢查。如果 xquery 表達(dá)式求值為非空節(jié)點(diǎn)列表,則返回 1;否則,返回 0。
nodes() 方法產(chǎn)生特定 xml 數(shù)據(jù)類型的實(shí)例,每個(gè)實(shí)例都將其上下文設(shè)置為 xquery 表達(dá)式所求值的不同節(jié)點(diǎn)。特定的 xml 數(shù)據(jù)類型支持 query()、value()、 nodes() 和 exist() 方法,并且可以用于 count(*) 聚合和 null 檢查。所有其他的使用都會產(chǎn)生錯(cuò)誤。
modify() 方法允許修改 xml 實(shí)例的某些部分,例如添加或刪除子樹,或者更新標(biāo)量值(如將書的價(jià)格從 9.99 替換為 39.99)。
例:使用 query() 方法
考慮下面的表 docs 的 xml 列 xcol 中的查詢,它提取 元素下的任何位置的 id 為 123 的 元素。該查詢也從整型主鍵列檢索值。select 列表中的 query() 方法會為生成 元素序列的表中的每一行進(jìn)行求值, 元素及其子樹是按照文檔順序進(jìn)行檢索的。對于每個(gè) xml 實(shí)例,如果沒有 id 為 123 的 元素或者其下沒有 元素,則不會返回結(jié)果,也就是說,query() 方法的返回值為 null。
select pk, xcol.query('/doc[@id = 123]//section') 
from  docsnull 返回值可以在外部 select 語句中過濾掉。或者也可以使用 exist() 方法,如下一個(gè)示例所示。
例:使用 exist() 方法
考慮下面的查詢,它在表 docs 的 xml 列 xcol 中包括 query() 和 exist() 方法。exist() 方法求路徑表達(dá)式 /doc[@id = 123] 的值,檢查是否存在頂層 元素,該元素具有一個(gè)稱為 id 的屬性,且其值為 123。對于每個(gè)這樣的行,select 子句中的 query() 方法都會進(jìn)行求值;在這個(gè)示例中,query() 方法在 元素下的任何位置都產(chǎn)生一個(gè) 元素序列。從 exist() 方法返回 0 的任何行都會被忽略。
select xcol.query('/doc[@id = 123]//section') 
from  docs
where xcol.exist ('/doc[@id = 123]') = 1例:使用 value() 方法
下面的查詢使用 value() 方法以 unicode 字符串的形式提取文檔第三部分的標(biāo)題。結(jié)果的 sql 類型的 nvarchar(max) 被指定為 value() 方法的第二個(gè)參數(shù)。xquery 函數(shù) data() 從 節(jié)點(diǎn)提取標(biāo)量值。
select xcol.value( 'data((/doc//section[@num = 3]/heading)[1])', 'nvarchar(max)') from docs
xquery 語言眾多的 xml 都來源于存儲在文件系統(tǒng)、web 服務(wù)或配置文件中的 office 文檔。事實(shí)上,以 xml 格式或作為虛擬 xml 文檔生成的數(shù)據(jù)正在不斷地增加。為了處理這些數(shù)量越來越多的數(shù)據(jù),一種強(qiáng)大的查詢語言 xquery 應(yīng)運(yùn)而生。在 xquery 語言規(guī)范(位于 http://www.w3.org/tr/xquery)中將選擇 xquery 的理由描述為:
| • | 一種巧妙地使用 xml 結(jié)構(gòu)的查詢語言,可以跨各種數(shù)據(jù)表示查詢,而不管這些數(shù)據(jù)是物理存儲在 xml 中,還是通過中間件被視為 xml。該規(guī)范描述了一種稱為 xquery 的查詢語言,它旨在能廣泛應(yīng)用于許多類型的 xml 數(shù)據(jù)源。 | 
| • | xquery 旨在滿足 w3c xml 查詢工作組 xml 查詢 1.0 要求和 xml 查詢用例中的用例所確定的要求。它是一種旨在使查詢簡潔易懂的語言。它還相當(dāng)?shù)仂`活,可以查詢大范圍的 xml 信息源,其中包括數(shù)據(jù)庫和文檔。 | 
| • | xquery 還可以概括為如下表述:xquery 語言之于 xml 正如 sql 語言之于關(guān)系數(shù)據(jù)庫。 | 
內(nèi)嵌于 t-sql 的 xquery 子集(位于 http://www.w3.org/tr/xquery/)是一種支持查詢 xml 數(shù)據(jù)類型的語言。這種語言正在由 worldwide web consortium (w3c) 進(jìn)行開發(fā)(目前處于最后請求狀態(tài)),所有主要的數(shù)據(jù)庫廠商(包括 microsoft 在內(nèi))都參與其中。我們的實(shí)現(xiàn)與 2003 年 11 月發(fā)布的 xquery 草案是一致的。
xquery 將 xpath 2.0 作為導(dǎo)航語言包括在內(nèi)。sql server 2005 的 xquery 實(shí)現(xiàn)提供了用于遍歷節(jié)點(diǎn) (for)、節(jié)點(diǎn)檢查 (where)、返回值 (return) 和排序 (order by) 的構(gòu)造。它也提供了用于在查詢過程中重新進(jìn)行數(shù)據(jù)構(gòu)形的元素構(gòu)造。
sql server 2005 還提供了用于 xml 數(shù)據(jù)類型的數(shù)據(jù)修改 (dml) 的語言構(gòu)造(請參閱下面的“數(shù)據(jù)修改”一節(jié)以獲得更多信息)。下面的示例演示了如何將 xquery 用于 xml 數(shù)據(jù)類型。
例:使用 xquery 中豐富的語言構(gòu)造
下面的查詢顯示了如何一起使用幾個(gè) xquery 語言構(gòu)造。它從 id 為 123 的文檔返回區(qū)域號為 3 和更高的區(qū)域中的標(biāo)題,并將其包裝在新標(biāo)記 中。
select pk, xcol.query('
  for $s in /doc[@id = 123]//section
  where $s/@num >= 3
  return <topic>{data($s/heading)}</topic>') 
from docs“for”遍歷 id 為 123 的<doc> 元素下的所有<section> 元素,并且將每個(gè)這樣的<section> 元素綁定到變量 $s。“where”確保區(qū)域號(<section> 元素的 @num 屬性)為 3 或更高。該查詢按照文檔順序返回區(qū)域<heading> 中的值,并且將其包裝在一個(gè)稱為<topic> 的構(gòu)造元素中。
查詢編譯和執(zhí)行sql 語句是由 sql 解析器解析的。當(dāng)它遇到 xquery 表達(dá)式時(shí),它就會跳轉(zhuǎn)到 xquery 編譯器,然后編譯 xquery 表達(dá)式。這會產(chǎn)生一個(gè)查詢樹,并將其嫁接到整個(gè)查詢的查詢樹上。
整個(gè)查詢樹會進(jìn)行查詢優(yōu)化并產(chǎn)生物理查詢計(jì)劃,該計(jì)劃是根據(jù)基于成本的評估得出的。showplan 輸出顯示了大部分關(guān)系運(yùn)算符和一些新的運(yùn)算符(例如,用于 xml 處理的 udx)。
查詢執(zhí)行與關(guān)系框架中的其余部分一樣,都是面向元組的。在表 docs 的每一行上都求 where 子句的值;這需要在運(yùn)行時(shí)解析 xml blob 以求出 xml 數(shù)據(jù)類型方法的值。如果條件滿足,則鎖定行,然后在行中求 select 子句的值。結(jié)果以 xml 數(shù)據(jù)類型的形式產(chǎn)生(用于 query() 方法),并且轉(zhuǎn)換成指定的目標(biāo)類型(用于 value() 方法)。
而如果該行不滿足 where 子句中的條件,它就會被忽略,執(zhí)行轉(zhuǎn)到下一行。
新聞熱點(diǎn)
疑難解答
圖片精選