如果編譯器不能確定在運(yùn)行時(shí)是否保證有 singleton 元素,則需要 singleton 元素的定位步驟、函數(shù)參數(shù)和運(yùn)算符(例如,eq)就會(huì)返回錯(cuò)誤。這種問(wèn)題常常因非類型化的數(shù)據(jù)而產(chǎn)生。例如,查找屬性需要 singleton 父元素;順序選擇單個(gè)的父節(jié)點(diǎn)就足夠了。
例:value() 方法中的類型檢查
下面的查詢是在非類型化的 xml 列中進(jìn)行的,它需要 //author/last-name 中的順序規(guī)范,因?yàn)?value() 方法需要 singleton 節(jié)點(diǎn)作為第一個(gè)參數(shù)。如果沒(méi)有,則編譯器就不能確定在運(yùn)行時(shí)是否只出現(xiàn)一個(gè)<last-name> 節(jié)點(diǎn)。
select xcol.value('(//author/last-name)[1]', 'nvarchar(50)') lastname
from  docs通過(guò)求 node()-value() 組合的值來(lái)提取屬性值可以不需要順序規(guī)范,如下一個(gè)示例所示。
例:已知的 singleton 元素
如下所示的 nodes() 方法為每個(gè)<book> 元素生成單獨(dú)的行。對(duì)<book> 節(jié)點(diǎn)求值的 value() 方法提取 @genre 的值,@genre 作為一個(gè)屬性,是 singleton 元素。
select nref.value('@genre', 'varchar(max)') lastname
from  docs cross apply xcol.nodes('//book') as r(nref)跨域查詢如果數(shù)據(jù)駐留在關(guān)系數(shù)據(jù)類型的列和 xml 數(shù)據(jù)類型的列的組合中,就可能需要編寫查詢來(lái)組合關(guān)系數(shù)據(jù)處理和 xml 數(shù)據(jù)處理。通過(guò)使用帶有 type 指令的 for xml,可以將關(guān)系列和 xml 列中的數(shù)據(jù)轉(zhuǎn)換成 xml 數(shù)據(jù)類型的實(shí)例,并使用 xquery 對(duì)其進(jìn)行查詢。相反地,可以從 xml 值生成行集,并且使用 t-sql 來(lái)對(duì)其進(jìn)行查詢,如下面的“從 xml 數(shù)據(jù)生成行集”一節(jié)所示。
編寫跨域查詢的一個(gè)更加方便和有效的方法是,使用 sql 變量的值,或者使用 xquery 或 xml 數(shù)據(jù)修改表達(dá)式中的列:
|||•
使用 sql:variable(),可以在 xquery 或 xml dml 表達(dá)式中應(yīng)用 sql 變量的值。
•
通過(guò) sql:column(),可以在 xquery 或 xml dml 上下文中使用來(lái)自關(guān)系列的值。
這種方法允許應(yīng)用程序參數(shù)化查詢,如下面的示例所示。sql:column() 的用法與前者類似,并且還帶來(lái)其他的好處。正如基于成本的查詢優(yōu)化器所確定的,可以使用列的索引來(lái)提高效率。此外,也可以使用計(jì)算列。
xml 和用戶定義的類型不允許與 sql:variable() 和 sql:column() 一起使用。
例:使用 sql:variable() 的跨域查詢
在這種查詢中,<book> 元素的 isbn 是使用 sql 變量 @isbn 來(lái)傳入的。代替使用常量,sql:variable() 提供 isbn 的值,并且該查詢可以用于搜索任何 isbn,而不只是 isbn 為 0-7356-1588-2 的 元素。
declare @isbn varchar(20)
set   @isbn = '0-7356-1588-2'
select xcol
from  docs
where  xcol.exist ('/book[@isbn = sql:variable("@isbn")]') = 1從 xml 數(shù)據(jù)生成行集在自定義屬性管理和數(shù)據(jù)交換場(chǎng)景中,應(yīng)用程序通常將 xml 數(shù)據(jù)的某些部分映射到行集。例如,為了將輸入?yún)?shù)表傳送到存儲(chǔ)過(guò)程或函數(shù),應(yīng)用程序需要將數(shù)據(jù)轉(zhuǎn)換成 xml,并且將其作為 xml 數(shù)據(jù)類型的參數(shù)傳入。在存儲(chǔ)過(guò)程或函數(shù)中,行集是從 xml 參數(shù)生成的。
sql server 2000 為此提供了 openxml()。它簡(jiǎn)化了從 xml 實(shí)例生成行集的過(guò)程,方法是指定行集的關(guān)系架構(gòu)以及將 xml 實(shí)例內(nèi)的值映射到行集中的列的方式。
另外,還可以使用 nodes() 方法來(lái)生成 xml 實(shí)例中的節(jié)點(diǎn)上下文,并且在 value()、query()、exist() 和 nodes() 方法中使用該節(jié)點(diǎn)上下文來(lái)生成所期望的行集。nodes() 方法接受 xquery 表達(dá)式,在 xml 列的每個(gè) xml 實(shí)例中對(duì)其進(jìn)行求值,并且有效地使用 xml 索引。下一個(gè)示例演示如何將 nodes() 方法用于行集生成。
|||例:從 xml 實(shí)例提取屬性
假定要提取名字不是“david”的作者的名和姓,將其作為由兩列(firstname 和 lastname)組成的一個(gè)行集。通過(guò)使用 nodes() 和 value() 方法,您可以達(dá)到此目的,如下所示:
select nref.value('first-name[1]', 'nvarchar(50)') firstname,
    nref.value('last-name[1]', 'nvarchar(50)') lastname
from  docs cross apply xcol.nodes('//author') as r(nref)
where nref.exist('.[first-name != "david"]') = 1在這個(gè)示例中,nodes('//author') 產(chǎn)生一個(gè)指向每個(gè) xml 實(shí)例的 元素的引用的行集。作者的名和姓是通過(guò)對(duì)與這些引用有關(guān)的 value() 方法求值來(lái)獲得的。要獲得好的性能,需要建立 xml 列的索引,這是下一部分的主題。
建立 xml 數(shù)據(jù)的索引
xml 數(shù)據(jù)是以內(nèi)部二進(jìn)制形式存儲(chǔ)的,存儲(chǔ)容量可以達(dá)到 2 gb。每個(gè)查詢?cè)谶\(yùn)行時(shí)一次或多次地解析表中每一行的 xml blob。這會(huì)使查詢處理的速度變得很慢。如果在工作負(fù)荷中常常需要進(jìn)行查詢,則建立 xml 列的索引是有好處的,不過(guò),這樣做必須考慮在修改數(shù)據(jù)的過(guò)程中維護(hù) xml 索引的成本。
xml 索引是通過(guò)一個(gè)新的 ddl 語(yǔ)句在類型化和非類型化的 xml 列中創(chuàng)建的。這為該列中的所有 xml 實(shí)例創(chuàng)建了一個(gè) b+ 樹(shù)。xml 列中的第一個(gè)索引是“主 xml 索引”。通過(guò)這個(gè)索引,可以在 xml 列中支持三種類型的次 xml 索引來(lái)加速普通類的查詢,如下一節(jié)所述。
主 xml 索引在基表(即定義 xml 列的表)的主鍵中,主 xml 索引需要聚集索引。它在 xml 節(jié)點(diǎn)的信息集項(xiàng)的一個(gè)子集中創(chuàng)建一個(gè) b+ 樹(shù)。b+ 樹(shù)的列表示標(biāo)記,例如元素和屬性名稱、節(jié)點(diǎn)值和節(jié)點(diǎn)類型。其他的列捕獲 xml 數(shù)據(jù)中的文檔順序和結(jié)構(gòu),以及從 xml 實(shí)例的根節(jié)點(diǎn)到每個(gè)節(jié)點(diǎn)的路徑,從而有效地對(duì)路徑表達(dá)式進(jìn)行求值。基表的主鍵在主 xml 索引中復(fù)制,以使索引行與基表行相關(guān)。
|||xml 架構(gòu)中給定的標(biāo)記和類型名稱被映射為整數(shù)值,而映射值存儲(chǔ)在 b+ 樹(shù)中以優(yōu)化存儲(chǔ)。索引中的路徑列按照相反的順序(即從節(jié)點(diǎn)到 xml 實(shí)例的根)存儲(chǔ)映射值的串聯(lián)。當(dāng)路徑后綴已知時(shí)(在一個(gè)路徑表達(dá)式中,如 //author/last-name),相反的表示使得可以匹配路徑值。
如果對(duì)基表進(jìn)行分區(qū),則需要以相同的方式對(duì)主 xml 索引進(jìn)行分區(qū),也就是使用相同的分區(qū)函數(shù)和分區(qū)架構(gòu)。
全部的 xml 實(shí)例都是從 xml 列檢索的(select * from docs 或 select xcol from docs)。需要 xml 數(shù)據(jù)類型方法的查詢使用主 xml 索引,從索引本身返回標(biāo)量值或 xml 子樹(shù)。
例:創(chuàng)建主 xml 索引
下面的語(yǔ)句在表 docs 的 xml 列 xcol 中創(chuàng)建一個(gè)名為 idx_xcol 的 xml 索引。
create primary xml index idx_xcol on docs (xcol)次 xml 索引一旦主 xml 索引創(chuàng)建完畢,就可以創(chuàng)建次 xml 索引來(lái)加速工作負(fù)荷中不同類的查詢。三種類型的次 xml 索引 — path、property 和 value — 分別對(duì)基于路徑的查詢、自定義屬性管理方案和基于值的查詢有利。
•
path 索引在主 xml 索引的列 (path, value) 中構(gòu)建 b+ 樹(shù)。該路徑的值是通過(guò)計(jì)算路徑表達(dá)式和節(jié)點(diǎn)的值得出的,如果提供了一個(gè)路徑值,則也可以使用所提供的值。在已知 path 索引開(kāi)始字段的情況下,查找 path 索引可以加速路徑表達(dá)式的求值。最常見(jiàn)的情況是在 select 語(yǔ)句的 where 子句中對(duì) xml 列使用 exist() 方法。
•
property 索引在主 xml 索引的列 (pk, path, value) 中創(chuàng)建 b+ 樹(shù),其中 pk 是基表的主鍵。此索引對(duì) xml 實(shí)例中的屬性值查找有利。
•
最后,value 索引在主 xml 索引的列 (value, path) 中創(chuàng)建一個(gè) b+ 樹(shù)。此索引對(duì)節(jié)點(diǎn)的值已知但是其路徑?jīng)]有準(zhǔn)確地在查詢中指定的查詢有利。這通常出現(xiàn)在祖先或自身 (descendant-or-self) 軸查詢中,例如,//author[last-name="howard"],其中, 元素可以出現(xiàn)在層次的任何一層。它還可以出現(xiàn)在“wildcard”查詢中,例如 /book [@* = "novel"],其中,查詢查找具有“novel”屬性值的 元素。此外,value 索引還可用于對(duì)類型化的 xml 進(jìn)行基于值的范圍掃描。
|||可以容納多達(dá) 128 層的 xml 層次;在插入和修改的過(guò)程中,如果 xml 實(shí)例包含更長(zhǎng)的路徑,則會(huì)被拒絕。
類似地,可以建立一個(gè)節(jié)點(diǎn)值的前 128 個(gè)字節(jié)的索引;系統(tǒng)中可以容納更長(zhǎng)的值,但是不會(huì)建立索引。
例:基于路徑的查找
假定下面的查詢?cè)诠ぷ髫?fù)荷中是常見(jiàn)的:
select xcol
from  docs
where xcol.exist ('/book[@genre = "novel"]') = 1路徑表達(dá)式 /book/@genre 和值“novel”對(duì)應(yīng)于 path 索引的鍵字段。因此,類型 path 的次 xml 索引有助于此工作負(fù)荷:
create xml index idx_xcol_path on docs (xcol)
  using xml index idx_xcol for path例:獲取對(duì)象的屬性
考慮下面的查詢,它從表 t 的每一行檢索書(shū)的“genre”、“title”和 isbn 屬性:
select xcol.value ('(/book/@genre)[1]', 'varchar(50)'),
  xcol.value ('(/book/title)[1]', 'varchar(50)'),
  xcol.value ('(/book/@isbn)[1]', 'varchar(50)')
from  docs屬性索引可用于這種情況,該索引創(chuàng)建如下:
create xml index idx_xcol_property on docs (xcol)
  using xml index idx_xcol for property例:基于值的查詢
在下面的查詢中,祖先或自己軸 (//) 指定了部分路徑,這樣,基于 isbn 值的查詢就可以從 value 索引的使用中受益:
select xcol
from  docs
where  xcol.exist ('//book[@isbn = "1-8610-0157-6"]') = 1value 索引創(chuàng)建如下:
|||create xml index idx_xcol_value on docs (xcol)
  using xml index idx_xcol for value內(nèi)容索引可以在 xml 列中創(chuàng)建全文本索引;這會(huì)建立 xml 值內(nèi)容的索引而忽略 xml 標(biāo)記。屬性值不是全文本索引的(因?yàn)樗鼈儽徽J(rèn)為是標(biāo)記的一部分),而元素標(biāo)記被用作標(biāo)記邊界。可以在 xml 列中創(chuàng)建 xml 和全文本索引,并且組合使用全文本搜索和 xml 索引。使用全文本索引作為第一個(gè)篩選器來(lái)縮小選擇范圍,接著再應(yīng)用 xquery 進(jìn)一步篩選。
使用 contains() 和 xquery contains() 的全文本搜索有不同的語(yǔ)義。后者是子字符串匹配,而前者是使用詞根檢索的標(biāo)記匹配。
例:在 xml 列中創(chuàng)建全文本索引
在 xml 列中創(chuàng)建全文本索引的步驟與在其他 sql 類型列中創(chuàng)建全文本索引的步驟是非常相似的。需要在基表中有一個(gè)唯一的鍵列。ddl 語(yǔ)句如下,其中,pk__docs__7f60ed59 是該表的單列主鍵索引:
create fulltext catalog ft as default
create fulltext index on dbo.docs (xcol) key index pk__docs__7f60ed59例:組合全文搜索和 xml 查詢
下面的查詢檢查 xml 值是否在書(shū)的標(biāo)題中包含單詞“secure”:
select *
from  docs
where contains(xcol,'secure')
and  xcol.exist('/book/title/text()[contains(.,"secure")]') =1contains() 方法使用全文本索引來(lái)產(chǎn)生一個(gè) xml 值的子集,它包含文檔中所有的單詞“secure”。exist() 子句確保單詞“secure”出現(xiàn)在書(shū)的標(biāo)題中。
使用 xml 索引執(zhí)行查詢
xml 索引可以加速查詢的執(zhí)行。查詢總是針對(duì) xml 列中的主 xml 索引進(jìn)行編譯(如果存在的話)。為整個(gè)查詢(包括關(guān)系部分和 xml 部分)制訂一個(gè)查詢計(jì)劃,該計(jì)劃可以通過(guò)數(shù)據(jù)庫(kù)引擎基于成本的優(yōu)化器進(jìn)行優(yōu)化。根據(jù)查詢優(yōu)化器的成本估算來(lái)選擇次 xml 索引。
|||xml 索引的目錄視圖
目錄視圖用于提供關(guān)于 xml 索引的元數(shù)據(jù)信息。目錄視圖 sys.indexes 包含帶有索引“type”3 的 xml 索引項(xiàng)。“name”列包含 xml 索引的名稱。
xml 索引也記錄在目錄視圖 sys.xml_indexes 中,它包含所有的 sys.indexes 列以及一些對(duì) xml 索引有意義的特別的列。列“secondary_type”中的值 null 表示主 xml 索引,值“p”、“r”和“v”分別代表 path、property 和 value 次 xml 索引。
可以從表值函數(shù) sys.fn_indexinfo() 中找到 xml 索引的空間使用。它提供的信息包括所占用的磁盤頁(yè)數(shù)、按字節(jié)計(jì)算的平均行大小、記錄數(shù),以及其他包括 xml 索引在內(nèi)的所有索引類型的信息。這些信息可用于每個(gè)數(shù)據(jù)庫(kù)分區(qū);xml 索引使用與基表相同的分區(qū)架構(gòu)和分區(qū)函數(shù)。
例:xml 索引的空間使用
select sum(pages)
from  sys.fn_indexinfo ('docs', 'idx_xcol_path' , default, 'detailed')這產(chǎn)生在表 t 的所有分區(qū)中 xml 索引 idx_xcol_path 所占用的磁盤頁(yè)數(shù)。如果沒(méi)有 sum() 函數(shù),則結(jié)果將會(huì)返回每個(gè)分區(qū)的磁盤頁(yè)使用。
xml 架構(gòu)處理在系統(tǒng)中,xml 架構(gòu)是可選的。如前所述,沒(méi)有綁定到 xml 架構(gòu)的 xml 數(shù)據(jù)類型被認(rèn)為是非類型化的;xml 節(jié)點(diǎn)值將作為 unicode 字符串存儲(chǔ),而 xml 實(shí)例需要進(jìn)行格式良好性檢查。可以建立非類型化 xml 列的索引。
要類型化 xml,可以將 xml 數(shù)據(jù)類型與已注冊(cè)到 xml 架構(gòu)集合的 xml 架構(gòu)相關(guān)聯(lián)。新的 ddl 語(yǔ)句允許創(chuàng)建一個(gè)或多個(gè) xml 架構(gòu)可以注冊(cè)到的 xml 架構(gòu)集合。綁定到 xml 架構(gòu)集合的 xml 列、參數(shù)或變量是根據(jù)該集合中的所有 xml 架構(gòu)進(jìn)行類型化的。在 xml 架構(gòu)集合中,類型系統(tǒng)標(biāo)識(shí)每個(gè)使用其目標(biāo)命名空間的 xml 架構(gòu)。
|||
另外,類型化的 xml 列中的選項(xiàng) document 或 content 分別指定了 xml 樹(shù)或片段是否可以存儲(chǔ)在 xml 列中。默認(rèn)為 content。對(duì)于 document,每個(gè) xml 實(shí)例都必須指定其頂層元素的目標(biāo)命名空間,該 xml 實(shí)例就是按照這個(gè)命名空間來(lái)進(jìn)行有效性檢查和類型化的。而對(duì)于 content,每個(gè)頂層元素都可以指定 xml 架構(gòu)集合中的任何一個(gè)目標(biāo)命名空間。該 xml 實(shí)例按照出現(xiàn)在實(shí)例中的所有目標(biāo)命名空間進(jìn)行有效性檢查和類型化。
例:創(chuàng)建 xml 架構(gòu)集合
假定要使用帶有目標(biāo)命名空間 http://mybooks 的 xml 架構(gòu)來(lái)類型化 xml 實(shí)例。可以創(chuàng)建一個(gè) xml 架構(gòu)集合 mycollection 并將該 xml 架構(gòu)作為 mycollection 的內(nèi)容,如下所示:
create xml schema collection mycollection as
'<xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema"
 xmlns="http://mybooks"
  elementformdefault="qualified"
 targetnamespace="http://mybooks">
 <xsd:element name="bookstore" type="bookstoretype" />
 <xsd:complextype name="bookstoretype">
  <xsd:sequence maxoccurs="unbounded">
   <xsd:element name="book" type="booktype" />
  </xsd:sequence>
 </xsd:complextype>
 <xsd:complextype name="booktype">
  <xsd:sequence>
   <xsd:element name="title" type="xsd:string" />
   <xsd:element name="author" type="authorname" />
   <xsd:element name="price" type="xsd:decimal" />
  </xsd:sequence>
  <xsd:attribute name="genre" type="xsd:string" />
  <xsd:attribute name="publicationdate" type="xsd:string" />
  <xsd:attribute name="isbn" type="xsd:string" />
 </xsd:complextype>
 <xsd:complextype name="authorname">
  <xsd:sequence>
   <xsd:element name="first-name" type="xsd:string" />
   <xsd:element name="last-name" type="xsd:string" />
  </xsd:sequence>
 </xsd:complextype>
</xsd:schema>'同時(shí)也為該 xml 架構(gòu)注冊(cè)到的 mycollection 創(chuàng)建了一個(gè)新的元數(shù)據(jù)實(shí)體。
新聞熱點(diǎn)
疑難解答
圖片精選