明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

Oracle XQuery查詢(xún)、構(gòu)建與轉(zhuǎn)換XML(3)

[摘要]查詢(xún)外部數(shù)據(jù)源 使用 XQuery,可以基于 XML 數(shù)據(jù)以及可以用 XML 表示的非 XML 數(shù)據(jù)生成 XML 文檔,無(wú)論其位置如何:無(wú)論是存儲(chǔ)在數(shù)據(jù)庫(kù)中、置于網(wǎng)站上、即時(shí)創(chuàng)建還是存儲(chǔ)在文件系統(tǒng)中。但要注意,Oracle XML DB 為針對(duì)數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù)進(jìn)行的 XML 操作提供了非常高的性...
查詢(xún)外部數(shù)據(jù)源

使用 XQuery,可以基于 XML 數(shù)據(jù)以及可以用 XML 表示的非 XML 數(shù)據(jù)生成 XML 文檔,無(wú)論其位置如何:無(wú)論是存儲(chǔ)在數(shù)據(jù)庫(kù)中、置于網(wǎng)站上、即時(shí)創(chuàng)建還是存儲(chǔ)在文件系統(tǒng)中。但要注意,Oracle XML DB 為針對(duì)數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù)進(jìn)行的 XML 操作提供了非常高的性能和可伸縮性。因此,如果您能夠完全控制所處理的數(shù)據(jù),則最好將它移動(dòng)到數(shù)據(jù)庫(kù)中。

正如您從前面的示例中了解到的,在 Oracle XQuery 實(shí)施中,doc 和 collection XQuery 函數(shù)用于訪問(wèn) Oracle XML DB 信息庫(kù)中存儲(chǔ)的 XML 文檔?梢酝ㄟ^(guò) XMLTable 和 XMLQuery SQL 函數(shù)中的 PASSING 子句動(dòng)態(tài)綁定外部數(shù)據(jù)源?紤]以下示例。假設(shè)您的公司要為那些致力于 XQ 項(xiàng)目的員工支付獎(jiǎng)金。因此,財(cái)務(wù)部發(fā)布了 empsbonus.xml 文件,其中包含有資格獲得獎(jiǎng)金的員工列表以及該列表中輸入的每個(gè)員工的獎(jiǎng)金數(shù)額。empsbonus.xml 文件可能如下所示:

100

1200





101

1000

在實(shí)際情況中,以上的 XML 文件可能置于網(wǎng)站上(因此可以通過(guò)互聯(lián)網(wǎng)獲得)、以文件形式存儲(chǔ)在本地文件系統(tǒng)中,或以文件資源形式存儲(chǔ)在 Oracle XML DB 信息庫(kù)中。就本示例而言,該文件位于網(wǎng)站上。為簡(jiǎn)單起見(jiàn),可以在目錄(Web 服務(wù)器在其中存儲(chǔ)可從 Web 看到的文檔)中創(chuàng)建一個(gè)員工文件夾,然后在該文件夾中插入 empsbonus.xml 文件,以便可以通過(guò)以下 URL 訪問(wèn) empsbonus.xml 文件:

http://localhost/employees/empsbonus.xml

接下來(lái),假設(shè)您需要基于 empsbonus.xml 文檔中存儲(chǔ)的數(shù)據(jù)創(chuàng)建一個(gè)報(bào)表。在該報(bào)表中,您可能不但要包含列表中顯示的獎(jiǎng)金數(shù)額以及每個(gè)員工的員工 ID,還要包含他/她的全名。因此,可以首先使用以下查詢(xún)生成一個(gè)新的 XML 文檔(假設(shè)您以 HR/HR 的身份連接):

SELECT XMLQuery(

'for $k in 1

return (

{for $i in ora:view("employees")/ROW,

$j in $emps/EMPLOYEES/EMPLOYEE

where $i/EMPLOYEE_ID = $j/EMPNO

return (

{xs:string($i/EMPLOYEE_ID)}

{xs:string(fn:concat($i/FIRST_NAME, " ", $i/LAST_NAME))}

{xs:integer($j/BONUS)}

)}
)'

PASSING xmlparse (document httpuritype

('http://localhost/employees/empsbonus.xml').getCLOB()) as "emps"

RETURNING CONTENT).getStringVal() as RESULT FROM DUAL;

以上查詢(xún)是一個(gè)有關(guān)如何使用 XQuery 基于 XML 和非 XML 數(shù)據(jù)(以不同的方式從不同的數(shù)據(jù)源中檢索)生成 XML 文檔的示例。具體而言,使用 ora:view() 函數(shù)訪問(wèn) HR 演示模式中的默認(rèn) employees 關(guān)系表,并使用 PASSING 子句中的 httpuritype() 函數(shù)借助于 HTTP 訪問(wèn) empsbonus.xml 文檔。然后,在 FLWOR 表達(dá)式的 return 子句中構(gòu)建新的 XML 文檔。最后,將獲得以下 XML 文檔:





100

Steven King

1200





101

Neena Kochhar

1000



解決性能問(wèn)題

正如您從前面的部分中了解到的,XQuery 是一種用于查詢(xún) Oracle 數(shù)據(jù)庫(kù)存儲(chǔ)的 XML 內(nèi)容的高效方法 - 無(wú)論您是處理本地存儲(chǔ)的 XMLType 數(shù)據(jù)還是查詢(xún)基于關(guān)系數(shù)據(jù)構(gòu)建的 XML 視圖。但根據(jù)對(duì)數(shù)據(jù)使用的存儲(chǔ)類(lèi)型的不同,XQuery 表達(dá)式的執(zhí)行性能可能迥然不同。尤其是,Oracle XML DB 可以?xún)?yōu)化基于由 ora:view 函數(shù)創(chuàng)建的 SQL/XML 視圖而構(gòu)建的 XQuery 表達(dá)式。對(duì)于 XMLType 表或列中存儲(chǔ)的 XML 數(shù)據(jù),只能對(duì)使用結(jié)構(gòu)化(對(duì)象-關(guān)系)存儲(chǔ)技術(shù)存儲(chǔ)的基于 XML 模式的 XMLType 數(shù)據(jù)進(jìn)行 XQuery 優(yōu)化。

所選擇的存儲(chǔ)模型并非是影響 XQuery 表達(dá)式執(zhí)行性能的唯一因素。在某些情況下,XQuery 表達(dá)式本身的結(jié)構(gòu)也可能導(dǎo)致性能問(wèn)題。要監(jiān)控 XQuery 表達(dá)式的性能,可以打印并檢查關(guān)聯(lián)的 EXPLAIN PLAN。在 SQL*Plus 中,只需設(shè)置 AUTOTRACE 系統(tǒng)變量,即可打印 SQL 優(yōu)化程序使用的執(zhí)行路徑。但要執(zhí)行該操作,請(qǐng)確保創(chuàng)建 PLUSTRACE 角色,然后將其授予連接到數(shù)據(jù)庫(kù)所使用的用戶(hù)。有關(guān)如何執(zhí)行此操作的信息,請(qǐng)參閱 Oracle 數(shù)據(jù)庫(kù) 10g 第 2 版 (10.2) 文檔中《SQL*Plus 用戶(hù)指南和參考》一書(shū)中的“調(diào)整 SQL*Plus”一章。以下示例演示了如何通過(guò)檢查 EXPLAIN PLAN 生成的執(zhí)行計(jì)劃來(lái)獲得好處。假設(shè)您已經(jīng)將 PLUSTRACE 角色授予默認(rèn)用戶(hù) OE,以 OE/OE 的身份登錄并運(yùn)行以下查詢(xún):

SET AUTOTRACE ON EXPLAIN


SELECT count(*)

FROM oe.purchaseorder, XMLTable(

'for $i in /PurchaseOrder/User

where $i = "CJOHNSON"

return $i'

PASSING OBJECT_VALUE) ptab;

這將生成以下輸出:

COUNT(*)

----------

9
Execution Plan

---------------------------------------------

Plan hash value: 4046110317
--------------------------------------------------------------

Id Operation Name Rows Bytes Cost (%CPU) Time

--------------------------------------------------------------

0 SELECT STATEMENT 1 226 29 (0) 00:00:01
  1   SORT AGGREGATE     1   226      
  2   NESTED LOOPS     10782   2379K   29 (0)   00:00:01  
 * 3   TABLE ACCESS FULL   PURCHASEORDER   1   226   5 (0)   00:00:01  
  4   COLLECTION ITERATOR P  XMLSEQUENCEFROMX         


Predicate Information (identified by operation id):

---------------------------------------------------
3 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<>

...

您可能對(duì)為以上查詢(xún)生成的執(zhí)行計(jì)劃并不滿意。尤其是,所處理的行數(shù)可能非常大。由于 SQL 調(diào)整的主要目標(biāo)是避免訪問(wèn)對(duì)結(jié)果沒(méi)有任何影響的行,因此可能要繼續(xù)調(diào)整查詢(xún)以?xún)?yōu)化性能。對(duì)查詢(xún)中包含的 XPath 表達(dá)式進(jìn)行重新建模后,可以再次重試它,如下所示:

SELECT count(*)

FROM oe.purchaseorder, XMLTable(

'for $i in /PurchaseOrder

where $i/User = "CJOHNSON"

return $i/User'

PASSING OBJECT_VALUE) ptab;
這次,輸出應(yīng)如下所示: 

COUNT(*)

----------

9


Execution Plan

---------------------------------------------------

Plan hash value: 3411896580
---------------------------------------------------------------

Id Operation Name Rows Bytes Cost (%CPU) Time

----------------------------------------------------------------

0 SELECT STATEMENT 1 29 7 (0) 00:00:01
  1   SORT AGGREGATE     1   29      
  2   NESTED LOOPS     1   29   7 (0)   00:00:01  
  3   FAST DUAL     1     2 (0)   00:00:01  
 * 4   TABLE ACCESS FULL   PURCHASEORDER   1   29   5 (0)   00:00:01  
Predicate Information (identified by operation id):

---------------------------------------------------
4 - filter("PURCHASEORDER"."SYS_NC00022$"='CJOHNSON' AND

SYS_CHECKACL("ACLOID","OWNERID",xmltype('<>

...

您可以看到,以上顯示的查詢(xún)生成相同的最終結(jié)果,但它們的執(zhí)行計(jì)劃并不相同。查看最后一個(gè)示例中的 XQuery 表達(dá)式,您可能會(huì)注意到它迭代頂層 PurchaseOrder 元素,其中的每個(gè) PurchaseOrder 元素都表示基于 PurchaseOrder XMLType 模式的表中的一行。這意味著實(shí)際上重寫(xiě) XQuery 表達(dá)式,以迭帶基礎(chǔ)對(duì)象表(用于存儲(chǔ)分解的 PurchaseOrder 文檔)中的行。與查詢(xún)要迭代不表示基礎(chǔ)表中的單個(gè)行的 XML 元素相比,該方法的性能更好一些。

但在某些情況下,很難發(fā)現(xiàn) XQuery 表達(dá)式的哪個(gè)構(gòu)造將使某些查詢(xún)的性能更好。這就是為什么最好在開(kāi)發(fā)階段使用調(diào)整工具的原因。