CREATE PRIMARY XML INDEX idx_xCol on T (xCol)
輔助 XML 索引
在創建主 XML 索引之後,您可能希望創建輔助 XML 索引來提高工作負荷中的不同種類查詢的速度。三種類型的輔助 XML 索引 - PATH、PROPERTY 和 VALUE 分別為基於路徑的查詢、自定義屬性管理場合和基於值的查詢提供幫助。PATH 索引在列中的所有 XML 實例上,按照文檔順序生成各個 XML 節點的 (path, value) 對的 B+ 樹。PROPERTY 索引創建各個 XML 實例中 (PK, path, value) 對的聚集 B+ 樹,其中 PK 是基表的主鍵。最後,VALUE 索引在 XML 列中的所有 XML 實例中,按照文檔順序創建各個節點的 (value, path) 對的 B+ 樹。
以下是創建上述一個或多個索引的一些准則:
• 如果工作負荷大量使用 XML 列中的路徑表達式,則 PATH 輔助 XML 索引可能會加快工作負荷的處理速度。最常見的例子是在 T-SQL 的 WHERE 子句中對 XML 列使用 exist() 方法。
• 如果您的工作負荷從單獨的使用路徑表達式的 XML 實例中檢索多個值,則將各個 XML 實例中的路徑聚集到 PROPERTY 索引中可能會很有用。這種情況通常出現在屬性包場合中,此時對象的屬性被獲取並且其主鍵值已知。
• 如果您的工作負荷涉及到查詢 XML 實例中的值,而不知道包含這些值的元素或屬性名稱,則您可能需要創建 VALUE 索引。這通常發生在子代軸查找中,例如 //author[last-name="Howard"],其中 元素可以出現在層次結構的任意級別上。這種情況還會發生在"通配符"查詢中,例如 /book [@* = "novel"],其中查詢將查找具有某個值為 "novel" 的屬性的 元素。
示例:基於路徑的查找
假設下面的查詢在您的工作負荷中很常見:
SELECT pk, xCol
FROM T
WHERE xCol.exist ('/book[@genre = "novel"]') = 1
路徑表達式 /book/@genre 和值 "novel" 對應於 PATH 索引的鍵字段。因此,PATH 類型的輔助 XML 索引對於該工作負荷很有用:
CREATE XML INDEX idx_xCol_Path on T (xCol)
USING XML INDEX idx_xCol FOR PATH
示例:獲取對象的屬性
請考慮下面的查詢,它從表 T 的各個行中檢索一本書的屬性"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 T
在這種情況下,屬性索引很有用,其創建方式如下所示:
CREATE XML INDEX idx_xCol_Property on T (xCol)
USING XML INDEX idx_xCol FOR PROPERTY
示例:基於值的查詢
在以下查詢中,子代軸或自身軸 (//) 指定了部分路徑,以便基於 ISBN 值的查找可以因為使用 VALUE 索引而受益:
SELECT xCol
FROM T
WHERE xCol.exist ('//book[@ISBN = "1-8610-0157-6"]') = 1
VALUE 索引按如下方式創建:
CREATE XML INDEX idx_xCol_Value on T (xCol)
USING XML INDEX idx_xCol FOR VALUE
XML 列上的全文索引
您可以在 XML 列上創建全文索引,從而將 XML 值的內容編入索引,而忽略 XML 標記。屬性值沒有被編入全文索引(因為它們被視為標記的一部分),並且元素標記被用作標記邊界。在某些情況下,可以將全文搜索與 XML 索引用法結合起來:
• 首先,使用 SQL 全文搜索篩選感興趣的 XML 值。
• 接下來,查詢這些 XML 值,這會使用 XML 列上的 XML 索引。
示例:將全文搜索與 XML 查詢結合起來
在 XML 列上創建全文索引之後,以下查詢將檢查 XML 值是否在書名中包含單詞"custom":
SELECT *
FROM T
WHERE CONTAINS(xCol,'custom')
AND xCol.exist('/book/title/text()[contains(.,"custom")]') =1
CONTAINS() 方法使用全文索引,將文檔中任何地方包含單詞"custom"的 XML 值組合為一個子集。exist() 子句確保單詞"custom"出現在書名中。
使用 CONTAINS() 和 XQuery contains() 的全文搜索具有不同的語義。後者是子字符串匹配,而前者則是使用單詞衍生的標記匹配。因此,如果要搜索標題中的字符串 "run",則 "run"、"runs" 和 "running" 都將匹配,因為全文 CONTAINS() 和 Xquery contains() 都滿足。然而,上述查詢不匹配標題中的單詞"customizable"。(全文 CONTAINS() 失敗,而 Xquery contains() 被滿足)。通常,對於純粹的子字符串匹配,應該刪除全文 CONTAINS() 子句。
而且,全文搜索采用單詞衍生,而 XQuery contains() 是一種字面匹配。這一區別將在下一個示例中闡述。
示例:使用單詞衍生對 XML 值進行全文搜索
通常情況下,不能排除示例:將全文搜索與 XML 查詢結合起來中的 XQuery contains() 檢查。請考慮查詢:
SELECT *
FROM T
WHERE CONTAINS(xCol,'run')
因為使用單詞衍生,所以文檔中的單詞"ran"匹配搜索條件。而且,使用 XQuery 時不會檢查搜索上下文。
在使用被全文索引的 AXSD 將 XML 分解到關系列中時,XML 視圖上的 XPath 查詢不會對基礎表執行全文搜索。
屬性提升
如果主要是對少量元素和屬性值進行查詢(例如,基於客戶 ID 查找客戶,即指定了 /Customer/@CustId 的值),您可能希望將這些數量提升到關系列中。當檢索了整個 XML 實例,但只對一小部分 XML 數據進行查詢時,這將很有用。在 XML 列上創建 XML 索引是沒有必要的;相反,可以將被提升的列編入索引。必須編寫查詢以使用提升的列(即,查詢優化器不會將對 XML 列的查詢重新定向到提升的列)。
提升的列可以是同一表中的計算列,也可以是表中單獨的、用戶維護的列。當從各個 XML 實例中提升唯一值(即單值屬性)時,這已足夠。然而,對於多值屬性,您必須為該屬性創建單獨的表,如下所述。
基於 XML 數據類型的計算列
可以使用能夠激活 XML 數據類型方法的用戶定義函數 (UDF) 來創建計算列。計算列的類型可以是任何 SQL 類型,包括 XML。以下示例說明了這一點。
示例:基於 XML 數據類型方法的計算列
為書籍的 ISBN 創建用戶定義的函數:
CREATE FUNCTION udf_get_book_ISBN (@xData XML)
RETURNS varchar(20)
BEGIN
DECLARE @ISBN varchar(20)
SELECT @ISBN = @xData.value('/book[1]/@ISBN', 'varchar(20)')
RETURN @ISBN
END
為 ISBN 向表中添加一個計算列:
ALTER TABLE T
ADD ISBN AS dbo.udf_get_book_ISBN(xCol)
可以用通常的方式將計算列編入索引。
示例:基於 XML 數據類型方法的計算列上的查詢
要獲取其 ISBN 為 0-7356-1588-2 的 ,可以改寫 XML 列上的查詢
SELECT xCol
FROM T
WHERE xCol.exist ('/book[@ISBN = "0-7356-1588-2"]') = 1
以使用計算列,如下所示:
SELECT xCol
FROM T
WHERE ISBN = '0-7356-1588-2'
可以創建一個用戶定義的函數,返回 XML 數據類型和使用該 UDF 的計算列。然而,無法在計算的 XML 列上創建 XML 索引。
創建屬性表
您可能希望將 XML 數據中的某些多值屬性提升到一個或多個表中,在這些表上創建索引,並且重定向查詢以使用這些表。典型的情形是一小部分屬性覆蓋了大部分查詢工作負荷。您可以執行以下操作:
• 創建一個或多個表以存放多值屬性。您可能發現采用以下處理方式會很方便:每個表存儲一個屬性,並且在屬性表中復制基表的主鍵以便與基表進行向後聯接。
• 如果您希望保持屬性的相對順序,則需要為相對順序引入一個單獨的列。
• 在 XML 列上創建觸發器以便維護屬性表。在觸發器中,執行以下操作:
• 使用 XML 數據類型方法(如 nodes() 和 value())在屬性表中插入和刪除行。(有關 nodes() 方法的詳細信息,請參閱 Value()、Nodes() 和 OpenXML()。)
• 在 CLR 中創建流式表值函數,以便在屬性表中插入和刪除行。
• 編寫查詢,以便對屬性表進行 SQL 訪問,以及對基表中的 XML 列進行 XML 訪問,這需要使用這些表的主鍵將其相互聯接。
示例:創建屬性表
假設您希望提升作者的名字。書籍有一個或多個作者,因此名字是一個多值屬性。每個名字都存儲在屬性表的單獨行中。在屬性表中復制了基表的主鍵以便向後聯接。
create table tblPropAuthor (propPK int, propAuthor varchar(max))
示例:創建用戶定義的函數以便從 XML 實例生成行集
下面的表值函數 udf_XML2Table 接受一個主鍵值和一個 XML 實例。它將檢索 元素的所有作者的名字,並返回(主鍵,名字)對行集。
create function udf_XML2Table (@pk int, @xCol XML)
returns @ret_Table table (propPK int, propAuthor varchar(max))
with schemabinding
as
begin
insert into @ret_Table
select @pk, nref.value('.', 'varchar(max)')
from @xCol.nodes('/book/author/first-name') R(nref)
return
end
示例:創建觸發器以填充屬性表
插入觸發器:在屬性表中插入行
create trigger trg_docs_INS on T for insert
as
declare @wantedXML XML
declare @FK int
select @wantedXML = xCol from inserted
select @FK = PK from inserted
insert into tblPropAuthor
select * from dbo.udf_XML2Table(@FK, @wantedXML)
刪除觸發器:基於刪除行的主鍵值,從屬性表中刪除行
create trigger trg_docs_DEL on T for delete
as
declare @FK int
select @FK = PK from deleted
delete tblPropAuthor where propPK = @FK
更新觸發器:在與更新的 XML 實例對應的屬性表中刪除現有行,並且在該屬性表中插入新行
create trigger trg_docs_UPD
on T
for update
as
if update(xCol) or update(pk)
begin
declare @FK int
declare @wantedXML XML
select @FK = PK from deleted
delete tblPropAuthor where propPK = @FK
select @wantedXML = xCol from inserted
select @FK = pk from inserted
insert into tblPropAuthor
select * from dbo.udf_XML2Table(@FK, @wantedXML)
end
示例:查找作者的名字為"David"的 XML 實例
可以在 XML 列上表示該查詢。另外,還可以在屬性表中搜索名字"David",然後與基表執行向後聯接以返回 XML 實例,如下所示:
SELECT xCol
FROM T JOIN tblPropAuthor ON T.pk = tblPropAuthor.propPK
WHERE tblPropAuthor.propAuthor = 'David'