この章では、Oracle XML DBの構造化(オブジェクト・リレーショナル)記憶域のXPathリライトの基礎について説明します。様々なSQL関数のXPath式引数のリライトについて詳しく説明します。
この章の内容は次のとおりです。
Oracle XML DBでは、XPath式を使用する問合せ(たとえば、XPath(XQuery)式を引数として取るXMLQuery
、XMLTable
、XMLExists
、updateXML
などのSQL関数を使用する問合せ)を最適化できることがよくあります。XPath式はXML文書に対して評価されますが、このときメモリー内でそのXML文書が構成されることはありません。
この最適化をXPathリライトと呼びます。これはXML問合せの最適化の適切なサブセットで、XPath式でないXQuery式(FLWOR式など)の最適化も行われます。また列に索引が存在する場合、XPathリライトによって、オプティマイザによる問合せの評価にその索引を使用できるようになります。
Oracle XML DBによってリライトできるXPath式は、Oracle XML DBでサポートされているXPath式の適切なサブセットです。機能性を損わずにXPath式をリライトできる場合は、リライト可能なXPath式を使用してください。
XPathリライトは、次のような状況(またはこれらの状況の組合せ)で可能です。
XMLType
データがオブジェクト・リレーショナル形式の列または表(構造化記憶域)に格納されている場合、またはリレーショナル・データに基づいてXMLType
ビューが構築されている場合。
XMLIndex
索引を使用する場合。「XMLIndex」を参照してください。
XMLType
データがバイナリXMLとして格納されている場合。ストリーミング評価の詳細は、「Oracle XML DBでのXMLTypeメソッドおよびSQL関数の処理」を参照してください。
この章では、第1のケースである、構造化XMLデータまたはXMLType
ビューを使用する問合せのリライトについて説明します。XMLType
ビューは、XML Schemaに基づくビューでも、XML Schemaに基づかないビューでもかまいません。XMLType
データの構造化記憶域は常に、XML Schemaに基づいています。この章の例は、XML Schemaに基づく表に関するものです。
例8-1は、XPath式を使用する単純な問合せのXPathリライトを示しています。
例8-1 XPathリライト
SELECT po.OBJECT_VALUE FROM purchaseorder po WHERE XMLCast(XMLQuery('$p/PurchaseOrder/Requestor' PASSING po.OBJECT_VALUE AS "p" RETURNING CONTENT) AS VARCHAR2(128)) = 'Sarah J. Bell';
XMLCast(XMLQuery...))
式は、発注書の要求者情報が格納される、基礎となるリレーショナル列にリライトされます。この問合せは次のようにリライトされます脚注1。
SELECT OBJECT_VALUE FROM purchaseorder p WHERE CAST (p."XMLDATA"."REQUESTOR" AS VARCHAR2(128)) = 'Sarah J. Bell';
表8-1は、XPathリライトでリライトされるいくつかのXPath式を示しています。
表8-1 基礎となるSQL構造体にリライトされるXPath式のサンプル
変換されるXPath式 | 説明 |
---|---|
単純なXPath式(
|
属性自体が単純なスカラー型またはオブジェクト型である場合、オブジェクト型の属性のみに対して全検索が行われます。 |
コレクション全検索式:
|
コレクション式の全検索が行われます。サポートされる軸は、child軸およびattribute軸のみです。 |
述語:
|
XPathの述語は、SQL述語にリライトされます。 |
リスト索引(位置指定述語):
|
コレクションのn番目の項目にアクセスするように索引がリライトされます。 |
ワイルド・カード全検索:
|
ワイルドカードを1つ以上の単純なXPath式に変換できる場合は、リライトされます。 |
descendant軸(XML Schemaに基づくデータのみ)、再帰なし:
|
ワイルド・カード式と同様です。 |
descendant軸(XML Schemaに基づくデータのみ)、再帰あり:
|
両方の条件を満たす場合、
|
XPath関数 |
一部のXPath関数がリライトされます。これらの関数には、 |
この項では、XPath式を使用する問合せで、次の操作を実行するための実行計画を使用する場合のガイドラインについて説明します。
問合せ計画の分析による、XPathリライトが行われるかどうかの判断。
2次索引を使用した問合せ実行の最適化。
これらのガイドラインを一緒に使用し、適用されるすべての事項を考慮します。
この章の残りの部分にも当てはまりますが、この項は、オブジェクト・リレーショナル形式(構造化記憶域)で格納されるXMLType
データのみに適用されます。
オブジェクト・リレーショナル記憶域のXPathリライトとは、XPath式で定義されるXMLフラグメントを選択する問合せが、基礎となるオブジェクト・リレーショナル表および列のSQL SELECT
文にリライトされることです。基礎となるこれらの表には、表外の表を含めることができます。
リライトされた問合せの実行計画は、問合せ対象のXMLType
データの基礎となるオブジェクト・リレーショナル表および列を参照します。
基礎となる表の名前は、XML要素または属性名から導出された場合、または適用されるXML Schemaによりxdb:defaultTable
注釈を使用して明示的に名前が付けられる場合に、意味を持つ場合があります。そうでない場合、名前はシステムにより生成され、明確な意味を持ちません。これらの名前には、対応するXML要素または属性の名前はを反映されません。また、システム生成の列の一部は非表示です。SQL describe
コマンドを使用すると、それらは表示できません。その場合でも実行計画には表示されます。
リライトされていない問合せの計画には、実表の名前のみが表示され、通常は、XMLExists
などのユーザー・レベルXML関数を参照します。問合せが最適化されているかどうかを判断するには、この違いを調べてください。実行計画に表示されるXML関数名は、実際には内部名(XMLEXISTS2
など)で、ユーザー・レベルの名前と多少異なることがあります。
例8-2に、Oracle XML DBがXPathリライトを実行できない場合に生成される実行計画の出力の種類を示します。ここでの計画はSQL/XML関数XMLExists
を使用する問合せに対するものです。計画の出力に、対応する内部関数XMLExists2
があり、これは問合せがリライトされないことを示します。
例8-2 XPathリライトを実行しない場合に生成される実行計画
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(XMLEXISTS2('$p/PurchaseOrder[User="SBELL"]' PASSING BY VALUE
SYS_MAKEXML('61687B202644E297E040578C8A175C1D',4215,"PO"."XMLEXTRA","PO"."X
MLDATA") AS "p")=1)
この場合、Oracle XML DBは、問合せのWHERE
句で指定した他の条件に基いて、事前フィルタされた結果セットを構成します。次に、この潜在的な結果セットの行をフィルタして、結果セットに属する行を決定します。フィルタリングでは、各文書でDOMが構築され、機能評価が実行され(DOM APIにより定義されたメソッドを使用)、各文書が結果セットのメンバーかどうかが判断されます。
XML Schemaを設計する場合は、注釈xdb:defaultTable
を使用して、基礎となる表に名前を付けます。この表はパフォーマンスが重要な問合せで選択する要素に対応します。これにより、実行計画でそれらを容易に識別できるようになり、問合せがリライトされたかどうかがわかります。
XPathリライトから生成された問合せには、SQL述語(WHERE
句)が含まれる場合があります。これは、元の問合せでXPath述語が使用されない場合や、元の問合せにSQL WHERE
句がない場合でも発生することがあります。
この場合は、SQL述語のターゲットとなる列に対して索引を作成したり、その列の関数適用に対して索引を作成することで、パフォーマンスを向上できる場合があります。例8-1は、WHERE
句を含む問合せのXPathリライトを示しています。例8-3は、この問合せの実行計画からの述語情報を示しています。
例8-3 実行計画の分析による列と索引の対応の特定
Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(CAST("PURCHASEORDER"."SYS_NC00021$" AS VARCHAR2(128))='Sarah J. Bell' AND SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege xmlns="http://xmlns.oracle.com/xdb/acl.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd http://xmlns.oracle.com/xdb/acl.xsd DAV:http://xmlns.oracle.com/xdb/dav.xsd "><read-properties/><read-contents/></privilege>'))=1)
述語情報では、発注書SYS_NC0021$
の要求者情報が格納される、基礎となるリレーショナル列のSQL関数cast
の使用に合せて、XMLCast(XMLQuery...))
式がリライトされることを示します。この列名はシステム生成されます。適用されるXML Schemaでは、注釈SQLName
を使用してこの列REQUESTOR
に名前を付けますが、実行計画では、システム生成されたこの名前を参照します。
これらの2つの名前(ユーザー定義およびシステム生成)は同じ列を参照するため、いずれかの名前を使用して、この列に対してBツリー索引を作成できます。また、extractValue
ショートカットを使用し、発注書の要求者データをターゲットとするXPath式を指定することで索引を作成することもできます。例8-4は、述語でターゲットとなっている列に対してBツリー索引を作成する3つの同等の方法を示しています。
例8-4 述語でターゲットとなっている列に対する索引の作成
CREATE INDEX requestor_index ON purchaseorder ("SYS_NC00021$"); CREATE INDEX requestor_index ON purchaseorder ("XMLDATA"."REQUESTOR"); CREATE INDEX requestor_index ON purchaseorder (extractvalue(OBJECT_VALUE, '/PurchaseOrder/Requestor'));
ただし、この問合せでは、リライトされた問合せの式に一致するファンクション式を使用してファンクション索引を作成することをお薦めします。例8-5に、これを示します。
例8-5 述語でターゲットとなっている列に対するファンクション索引の作成
CREATE INDEX requestor_index ON purchaseorder (cast("XMLDATA"."REQUESTOR" AS VARCHAR2(128)));
例8-6は、索引が取り出されることを示す実行計画を示しています。
例8-6 索引が選択されていることを示す実行計画
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 524 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| PURCHASEORDER | 1 | 524 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | REQUESTOR_INDEX | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege
xmlns="http://xmlns.oracle.com/xdb/acl.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd
http://xmlns.oracle.com/xdb/acl.xsd
DAV:http://xmlns.oracle.com/xdb/dav.xsd">
<read-properties/><read-contents/></privilege>'))=1)
2 - access(CAST("SYS_NC00021$" AS VARCHAR2(128))='Sarah J. Bell')
この問合せの場合では、元のファンクション式によってXMLCast
がXMLQuery
に適用され、単一要素のRequestor
がターゲットになります。これは、CREATE INDEX
文でこうしたファンクション式をショートカットとして直接使用できる特殊なケースです。基礎となるスカラー・データ上に索引を作成するように、その文がリライトされます。例8-7はXPath式をターゲットとしており、対応するオブジェクト・リレーショナル列をターゲットとする例8-5と同じ結果になります。
例8-7 述語でターゲットとなっている列に対するファンクション索引の作成
CREATE INDEX requestor_index ON purchaseorder po (XMLCast(XMLQuery('$p/PurchaseOrder/Requestor' PASSING po.OBJECT_VALUE AS "p" RETURNING CONTENT) AS VARCHAR2(128)));
関連項目: XMLQuery に適用されるXMLCast のショートカットおよび単一のデータに索引付けするためのextractValue ショートカットの使用方法の詳細は、「繰り返し使用しないtext()ノードまたは属性値の索引付け」を参照してください。 |
Ordered Collection TableまたはXMLType
インスタンスとしてコレクションが格納されている場合は、コレクションのメンバーに直接アクセスできます。コレクションの各メンバーは表内の行になるため、SQLで直接アクセスできます。
このようなコレクション・メンバーに索引付けすることによって、パフォーマンスを向上できます。これを実行するには、コレクションXML要素またはその属性、および疑似NESTED_TABLE_ID
に対応するオブジェクト属性に対して、コンポジット索引を作成します。
例8-8では、部品番号717951002372(Id
属性の値が717951002372
のPart
要素)の発注を含む文書からReference
要素を検索する問合せの実行計画を示します。LineItem
要素のコレクションは、Ordered Collection Table、lineitem_table
に行として格納されています。
例8-8 コレクション要素の選択の実行計画
SELECT XMLCast(XMLQuery('$p/PurchaseOrder/Reference' PASSING OBJECT_VALUE AS "p" RETURNING CONTENT) AS VARCHAR2(4000)) "Reference" FROM purchaseorder WHERE XMLExists('$p/PurchaseOrder/LineItems/LineItem/Part[@Id="717951002372"]' PASSING OBJECT_VALUE AS "p"); ------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 122 | 16 (13)| 00:00:01 | | 1 | NESTED LOOPS | | | | | | | 2 | NESTED LOOPS | | 1 | 122 | 16 (13)| 00:00:01 | | 3 | SORT UNIQUE | | 1 | 50 | 14 (8)| 00:00:01 | |* 4 | TABLE ACCESS FULL | LINEITEM_TABLE | 1 | 50 | 14 (8)| 00:00:01 | |* 5 | INDEX UNIQUE SCAN | LINEITEM_TABLE_MEMBERS | 1 | | 0 (0)| 00:00:01 | | 6 | TABLE ACCESS BY INDEX ROWID| PURCHASEORDER | 1 | 72 | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter("SYS_NC00009$" IS NOT NULL AND "SYS_NC00011$"='717951002372') 5 - access("NESTED_TABLE_ID"="PURCHASEORDER"."SYS_NC0003400035$")
実行計画は、Ordered Collection Table、lineitem_table
の全体スキャンを示しています。この計画は、purchaseorder
表内の文書の数が数百しかなければ許容されますが、表内に数千または数百万の文書がある場合は許容されません。
このような問合せのパフォーマンスを改善するには、属性Id
の値を指定した疑似列NESTED_TABLE_ID
に直接アクセスできる索引を作成します。しかし、Oracle XML DBでは、XPath式を直接使用してコレクションに対する索引を作成することはできません。索引を作成するには、LineItem
要素の管理に使用するSQLオブジェクトの構造を理解する必要があります。その情報に基づいて、従来のオブジェクト・リレーショナルSQLを使用して必要な索引を作成できます。
ここでは、要素LineItem
はオブジェクト・タイプlineitem_t
のインスタンスとして格納されています。また、要素Part
はSQLデータ型part_t
のインスタンスとして格納されています。XML属性Id
は、オブジェクト属性part_number
にマップされています。これらの情報に基づいて、例8-9に示すように、属性part_number
および疑似列NESTED_TABLE_ID
に対するコンポジット索引を作成できます。この索引によって、必要な部品を参照するLineItem
要素が含まれた発注書に直接アクセスできます。
脚注の凡例
脚注1: この例では、サンプルのデータベース・スキーマOE
とその表purchaseorder
を使用しています。この表のXML Schemaには、REQUESTOR
などのSQLオブジェクト属性名を指定するために、属性SQLName
で注釈が付けられています(例3-10を参照)。このような注釈を使用しないと、例では、p."XMLDATA"."
.REQUESTOR
"
ではなくp."XMLDATA"."
Requestor
"
が使用されます。