この章では、構造化されたXML Schemaに基づくXMLTypeオブジェクトを格納するための高度なテクニックについて説明します。
|
関連項目:
|
この章の内容は次のとおりです。
XML Schemaは、デフォルトのマッピングを使用して、オブジェクト・リレーショナル型から自動で生成できます。パッケージDBMS_XMLSCHEMA内のPL/SQL関数generateSchemaおよびgenerateSchemasは、オブジェクト型の名前が含まれる文字列と、Oracle XML DBのXML Schemaが含まれる文字列を取ります。
ファンクションgenerateSchemaは、XML Schemaを含むXMLTypeを戻します。オプションで、任意のオブジェクト型によって参照されるすべての型に対して、または最上位の型のみに制限してXML Schemaを生成できます。
ファンクションgenerateSchemasも似ていますが、これはXMLSequenceType値を戻します。これはXMLTypeインスタンスのVARRAYであり、それぞれのインスタンスは別の名前空間に対応するXML Schemaです。また、オプションで追加の引数を取り、優先されるXML Schemaの場所のルートURLを指定します。
http://xmlns.oracle.com/xdb/schemas/<schema>.xsd
オプションで、Oracle XML DBにXML Schemaを登録するために使用できる注釈付きXML Schemaも生成できます。
例8-1 関数GENERATESCHEMAを使用したXML Schemaの生成
たとえば、次のオブジェクト型が設定されているとします。
CREATE TYPE employee_t AS OBJECT(empno NUMBER(10),
ename VARCHAR2(200),
salary NUMBER(10,2)):
次のとおり、この型に対するスキーマを生成できます。
SELECT DBMS_XMLSCHEMA.generateschema('T1', 'EMPLOYEE_T') FROM DUAL;
これによって、型employee_tに対応するスキーマが戻されます。このスキーマでは、EMPLOYEE_Tという名前の要素およびEMPLOYEE_TTypeという名前のcomplexTypeが宣言されます。このスキーマには、http://xmlns.oracle.com/xdbに存在する他の注釈が含まれます。
DBMS_XMLSCHEMA.GENERATESCHEMA('T1', 'EMPLOYEE_T')
------------------------------------------------------------------------
<xsd:schema targetNamespace="http://ns.oracle.com/xdb/T1"
xmlns="http://ns.oracle.com/xdb/T1"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.oracle.com/xdb
http://xmlns.oracle.com/xdb/XDBSchema.xsd">
<xsd:element name="EMPLOYEE_T" type="EMPLOYEE_TType"
xdb:SQLType="EMPLOYEE_T" xdb:SQLSchema="T1"/>
<xsd:complexType name="EMPLOYEE_TType">
<xsd:sequence>
<xsd:element name="EMPNO" type="xsd:double" xdb:SQLName="empno"
xdb:SQLType="NUMBER"/>
<xsd:element name="ENAME" type="xsd:string" xdb:SQLName="ename"
xdb:SQLType="VARCHAR2"/>
<xsd:element name="SALARY" type="xsd:double" xdb:SQLName="salary"
xdb:SQLType="NUMBER"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
XML Schemaに基づいてXMLType表を作成した後、属性の親要素に一意制約を追加する方法を考えてみます。たとえば、自己循環する要素(コレクション)の属性に基づいて一意キーを作成することが考えられます。複数回出現する要素に制約を作成するには、VARRAYをOrdered Collection Table(OCT)として格納します。したがって、OCTに対して制約を作成できます。
例8-2に示すXML Schemaを使用すると、要素<PhoneNumber>の属性Noが複数回出現します。この例は、指定のインスタンス・ドキュメント内で同一の電話番号を繰り返せないことを保証する一意制約を追加する方法を示しています。
例8-2 属性の親要素への一意制約の追加
BEGIN DBMS_XMLSCHEMA.registerschema('emp.xsd',
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<xs:element name="Employee" xdb:SQLType="EMP_TYPE">
<xs:complexType>
<xs:sequence>
<xs:element name="EmployeeId" type="xs:positiveInteger"/>
<xs:element name="PhoneNumber" maxOccurs="10">
<xs:complexType>
<xs:attribute name="No" type="xs:integer"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>',
TRUE,
TRUE,
FALSE,
FALSE);
END;/
PL/SQL procedure successfully completed.
CREATE TABLE emp_tab OF XMLType
XMLSCHEMA "emp.xsd" ELEMENT "Employee"
VARRAY XMLDATA."PhoneNumber" STORE AS TABLE phone_tab;
Table created.
ALTER TABLE phone_tab ADD UNIQUE (NESTED_TABLE_ID, "No"); Table altered.
INSERT INTO emp_tab
VALUES(XMLType('<Employee>
<EmployeeId>1234</EmployeeId>
<PhoneNumber No="1234"/>
<PhoneNumber No="2345"/>
</Employee>').createSchemaBasedXML('emp.xsd'));
1 row created.
INSERT INTO emp_tab
VALUES(XMLType('<Employee>
<EmployeeId>3456</EmployeeId>
<PhoneNumber No="4444"/>
<PhoneNumber No="4444"/>
</Employee>').createSchemaBasedXML('emp.xsd'));
これによって、予期した結果が戻ります。
*ERROR at line 1:ORA-00001: unique constraint (SCOTT.SYS_C002136) violated
この例の制約は、個々のコレクションに対して適用され、すべてのインスタンスには適用されません。制約は、コレクションID列を持つ連結索引を作成することで適用されます。全インスタンス・ドキュメントのコレクションすべてに制約を適用するには、コレクションID列を省略します。
|
注意: 機能上の制約は、バイナリXMLとして格納されているXMLTypeデータに対する一意キーまたは外部キーの制約としてのみ作成できます。 |
デフォルトでは、XMLTypeデータがオブジェクト・リレーショナル形式で格納される場合、子XML要素は埋込みSQLオブジェクト属性にマップされます。ただし、表外に格納することによってパフォーマンスが向上する場合もあります。そのような場合は、XML Schema注釈属性SQLInlineをfalseに設定すると、Oracle XML DBによってREF属性が埋め込まれたSQLオブジェクト型が生成されます。REFは、表外に格納されるXMLフラグメントに対応するXMLTypeの他のインスタンスを指します。また、デフォルトのXMLType表が作成され、この表に表外のフラグメントが格納されます。
図8-1に、表外に格納するためのSQLへのcomplexTypeのマッピングを示します。
例8-3 表外に格納するためのSQLInLineのfalse設定
この例では、要素Addrの属性xdb:SQLInLineがfalseに設定されています。結果のSQLオブジェクト型obj_t2には、REF属性が埋め込まれたXMLType型の列が含まれています。REF属性は、表addr_tabのオブジェクト型obj_t1の他のXMLTypeインスタンスを指しています。表addr_tabは表外に格納されています。列streetおよびcityが含まれています。
DECLARE
doc VARCHAR2(3000) :=
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.oracle.com/emp.xsd"
xmlns:emp="http://www.oracle.com/emp.xsd"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<complexType name="EmpType" xdb:SQLType="EMP_T">
<sequence>
<element name="Name" type="string"/>
<element name="Age" type="decimal"/>
<element name="Addr"
xdb:SQLInline="false"
xdb:defaultTable="ADDR_TAB">
<complexType xdb:SQLType="ADDR_T">
<sequence>
<element name="Street" type="string"/>
<element name="City" type="string"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
<element name="Employee" type="emp:EmpType"
xdb:defaultTable="EMP_TAB"/>
</schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema(
SCHEMAURL => 'emp.xsd',
SCHEMADOC => doc,
ENABLE_HIERARCHY => DBMS_XMLSCHEMA.ENABLE_HIERARCHY_NONE);
END;
/
このXML Schemaを登録すると、Oracle XML DBによって、次の型およびXMLType表が生成されます。
DESCRIBE emp_tab Name Null? Type ----------------------------- -------- ---------------------------------------------------------- TABLE of SYS.XMLTYPE(XMLSchema "emp.xsd" Element "Employee") STORAGE Object-relational TYPE "EMP_T" DESCRIBE addr_tab Name Null? Type ----------------------------- -------- -------------------------------------------------------- TABLE of SYS.XMLTYPE(XMLSchema "emp.xsd" Element "Addr") STORAGE Object-relational TYPE "ADDR_T"
DESCRIBE emp_t
emp_t is NOT FINAL
Name Null? Type
----------------------------- -------- --------------------
SYS_XDBPD$ XDB.XDB$RAW_LIST_T
Name VARCHAR2(4000 CHAR)
Age NUMBER
Addr REF OF XMLTYPE
DESCRIBE addr_t
Name Null? Type
----------------------------- -------- --------------------
SYS_XDBPD$ XDB.XDB$RAW_LIST_T
Street VARCHAR2(4000 CHAR)
City VARCHAR2(4000 CHAR)
表emp_tabには全従業員の情報が格納され、表外の、表addr_tabに格納されている住所情報を指すオブジェクト参照が含まれています。
このモデルのメリットは、表外の表(addr_tab)を直接問い合せ、住所情報を参照できることです。例8-4は、全従業員について固有の都市情報を取得するために、表addr_tabを直接問い合せる場合を示しています。
例8-4 表外の表の問合せ
INSERT INTO emp_tab
VALUES
(XMLType('<x:Employee
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:x="http://www.oracle.com/emp.xsd"
xsi:schemaLocation="http://www.oracle.com/emp.xsd emp.xsd">
<Name>Abe Bee</Name>
<Age>22</Age>
<Addr>
<Street>A Street</Street>
<City>San Francisco</City>
</Addr>
</x:Employee>'));
INSERT INTO emp_tab
VALUES
(XMLType('<x:Employee
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:x="http://www.oracle.com/emp.xsd"
xsi:schemaLocation="http://www.oracle.com/emp.xsd emp.xsd">
<Name>Cecilia Dee</Name>
<Age>23</Age>
<Addr>
<Street>C Street</Street>
<City>Redwood City</City>
</Addr>
</x:Employee>'));
. . .
SELECT DISTINCT extractValue(OBJECT_VALUE, '/Addr/City') AS city FROM addr_tab; CITY ------------- Redwood City San Francisco
この格納モデルのデメリットは、Employee要素全体を取得するために、住所に関する別の表にアクセスする必要がある点です。
表外に格納されている要素を含むXPath式はリライトできます。問合せでは、表外の表との結合が行われます。例8-5は、そのような問合せを示したものです。例8-6との比較のために、この問合せの実行計画の断片を示します。
例8-5 表外の表のXPathリライト
SELECT XMLCast(XMLQuery('declare namespace x = "http://www.oracle.com/emp.xsd"; (: :)
/x:Employee/Name' PASSING OBJECT_VALUE RETURNING CONTENT)
AS VARCHAR2(20))
FROM emp_tab
WHERE XMLExists('declare namespace x = "http://www.oracle.com/emp.xsd"; (: :)
/x:Employee/Addr[City="San Francisco"]' PASSING OBJECT_VALUE);
XMLCAST(XMLQUERY(...
--------------------
Abe Bee
Eve Fong
George Hu
Iris Jones
Karl Luomo
Marina Namur
Omar Pinano
Quincy Roberts
8 rows selected.
|* 3 | INDEX RANGE SCAN | ADDR_CITY_IDX | 1 | | 1 (0)| 00:00:01 |
| 2 | TABLE ACCESS BY INDEX ROWID| ADDR_TAB | 1 | 2012 | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMP_TAB | 16 | 32464 | 2 (0)| 00:00:01 |
ここのXQuery式はSQL EXISTS副問合せにリライトされています。この副問合せは、表addr_tabを問い合せ、表addr_tabのオブジェクト識別子列を使用して、この表を表emp_tabと結合します。オプティマイザは表emp_tabおよびaddr_tabの全表スキャンを使用します。addr_tabに多数のエントリがある場合は、cityに索引を作成することで、この問合せの効率を高めることができます。例8-6を参照してください。例8-5と同じ問合せに対応する実行計画の断片は、cityの索引が取り出されることを示しています。
例8-6 表外の表での索引の使用
CREATE INDEX addr_city_idx ON addr_tab (extractValue(OBJECT_VALUE, '/Addr/City'));
| 2 | TABLE ACCESS BY INDEX ROWID| ADDR_TAB | 1 | 2012 | 1 (0)| 00:00:01 |
|* 3 | INDEX RANGE SCAN | ADDR_CITY_IDX | 1 | | 1 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL | EMP_TAB | 16 | 32464 | 2 (0)| 00:00:01 |
|
注意: オブジェクト・リレーショナル形式で格納されるXMLType表に対して、オプティマイザ用に統計情報を収集する場合、XML Schemaによって定義されているすべての表、つまりUSER_XML_TABLES内のすべての表について統計情報を収集することをお薦めします。そのためには、プロシージャDBMS_STATS.gather_schema_statsを使用するか、対象の各表に対してDBMS_STATS.gather_table_statsを使用します。これによりオプティマイザは、XMLTypeデータを格納するために使用されているすべての依存表について情報を取得できます。 |
表外に格納するリスト項目もマップできます。この場合、親要素には、単一のREF列ではなく、コレクションのメンバーを指すREF値のVARRAYが挿入されます。たとえば、各従業員の住所リストがあり、そのリストが表外の記憶域にマップされているとします。
例8-7 コレクションの表外格納
DECLARE
doc VARCHAR2(3000) :=
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.oracle.com/emp.xsd"
xmlns:emp="http://www.oracle.com/emp.xsd"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<complexType name="EmpType" xdb:SQLType="EMP_T">
<sequence>
<element name="Name" type="string"/>
<element name="Age" type="decimal"/>
<element name="Addr" xdb:SQLInline="false"
maxOccurs="unbounded" xdb:defaultTable="ADDR_TAB">
<complexType xdb:SQLType="ADDR_T">
<sequence>
<element name="Street" type="string"/>
<element name="City" type="string"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
<element name="Employee" type="emp:EmpType"
xdb:defaultTable="EMP_TAB"/>
</schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema(
SCHEMAURL => 'emp.xsd',
SCHEMADOC => doc,
ENABLE_HIERARCHY => DBMS_XMLSCHEMA.ENABLE_HIERARCHY_NONE);
END;
/
このXML Schemaを登録する場合、Oracle XML DBは表emp_tabおよびaddr_tab、それに型emp_tおよびaddr_tを生成します。例8-3を参照してください。ただしこの場合は、型emp_tに、単一のREF属性ではなく、住所に対するREF値のVARRAYが含まれます。
DESCRIBE emp_t
emp_t is NOT FINAL
Name Null? Type
-------------------------------------- -------- --------------------------
SYS_XDBPD$ XDB.XDB$RAW_LIST_T
Name VARCHAR2(4000 CHAR)
Age NUMBER
Addr XDB.XDB$XMLTYPE_REF_LIST_T
デフォルトでは、XML Schema属性storeVarrayAsTableの値はtrueです。これはこのREF値のVARRAYが表外の中間表に格納されることを意味します。これは、XML Schema登録では、今あげた表と型が作成されるだけでなく、REF値のリストを格納する中間表も作成されるということです。この表にはシステム生成された名前がありますが、たとえばそれに対して索引を作成するために、名前を変更することができます。
例8-8 REF値の中間表名の変更
DECLARE
gen_name VARCHAR2 (4000);
BEGIN
SELECT TABLE_NAME INTO gen_name FROM USER_NESTED_TABLES
WHERE PARENT_TABLE_NAME = 'EMP_TAB';
EXECUTE IMMEDIATE 'RENAME "' || gen_name || '"TO emp_tab_reflist';
END;
/
DESCRIBE emp_tab_reflist
Name Null? Type
----------------------- -------- ----------------
COLUMN_VALUE REF OF XMLTYPE
例8-9は、サンフランシスコを拠点とする全従業員の名前と居住している町を選択する問合せを示しています。この例では、City要素で住所表を問い合せ、従業員表を使用して逆方向に結合します。示されている実行計画の断片は、表emp_tab_reflistとemp_tabの間の結合を示しています。
例8-9 表外のコレクションのXPathリライト
SELECT em.name, ad.street
FROM emp_tab,
XMLTable(XMLNAMESPACES ('http://www.oracle.com/emp.xsd' AS "x"),
'/x:Employee' PASSING OBJECT_VALUE
COLUMNS name VARCHAR2(20) PATH 'Name') em,
XMLTable(XMLNAMESPACES ('http://www.oracle.com/emp.xsd' AS "x"),
'/x:Employee/Addr' PASSING OBJECT_VALUE
COLUMNS street VARCHAR2(20) PATH 'Street',
city VARCHAR2(20) PATH 'City') ad
WHERE ad.city = 'San Francisco';
NAME STREET
-------------------- --------------------
Abe Bee A Street
Eve Fong E Street
George Hu G Street
Iris Jones I Street
Karl Luomo K Street
Marina Namur M Street
Omar Pinano O Street
Quincy Roberts Q Street
8 rows selected.
| 4 | TABLE ACCESS FULL | EMP_TAB_REFLIST | 32 | 640 | 2 (0)| 00:00:01 | | 5 | TABLE ACCESS BY INDEX ROWID| EMP_TAB | 1 | 29 | 1 (0)| 00:00:01 | |* 6 | INDEX UNIQUE SCAN | SYS_C005567 | 1 | | 0 (0)| 00:00:01 |
REF値の索引を中間表emp_tab_reflistに作成することでパフォーマンスを向上できます。これによって、Oracle XML DBは、住所表を問い合せて、関連する行へのオブジェクト参照(REF)を取得し、そのオブジェクト参照をREF値のリストが格納されている中間表に結合し、従業員表を使用してその中間表を逆方向に結合することができます。
REF値に索引を作成できるのは、REFに有効範囲が設定されている場合、または参照制約がある場合のみです。REF列に対する有効範囲決定では、特定の表のオブジェクトに対するポインタのみが格納されます。表emp_tab_reflistのREF値は、表addr_tabのオブジェクトのみを参照します。したがって、例8-10に示すように、REF列に対して有効範囲制約と索引を作成できます。
例8-10 REFへの索引を使用した表外のコレクションのXPathリライト
ALTER TABLE emp_tab_reflist ADD SCOPE FOR (COLUMN_VALUE) IS addr_tab;
CREATE INDEX reflist_idx ON emp_tab_reflist (COLUMN_VALUE);
例8-9と同じ問合せに対応する実行計画の断片が、索引reflist_idxが取り出されることを示しています。例8-9と比較してください。
| 4 | TABLE ACCESS BY INDEX ROWID| EMP_TAB_REFLIST | 1 | 20 | 1 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | REFLIST_IDX | 1 | | 0 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | EMP_TAB | | | | |
|* 7 | INDEX UNIQUE SCAN | SYS_C005567 | 1 | | 0 (0)| 00:00:01 |
問合せ内の選択性の高い述語が従業員表にあるような一部の場合には、REF値のVARRAYを表emp_tabの行に格納するために、XML Schema属性storeVarrayAsTableをfalseに設定することをお薦めします。表内にVARRAYを格納すると、2つの表emp_tabおよびaddr_tabに関連する問合せが、常にemp_tabから実行されるように効率的に強制できます。このため、住所表から逆方向に結合する効率的な方法はありません。これは、従業員数が多い場合、この手法が不適切であることを意味します。高コストのemp_tab表の全表スキャンが含まれるためです。
デフォルトでは、XML Schema URLの名前は、常に現行のユーザーの範囲内で参照されます。そのため、データベース・ユーザーによってXML Schema URLが指定された場合、まず現行のユーザーが所有するローカルXML Schemaの名前として解決されます。
対応するローカルXML Schemaが存在しない場合は、グローバルXML Schemaの名前として解決されます。
対応するグローバルXML Schemaも存在しない場合は、Oracle XML DBでエラーが発生します。
前述の場合にXML Schemaの明示的な参照を可能にするため、Oracle XML DBでは、完全修飾されたXML Schema URLという概念をサポートしています。この構成では、XML Schema URLの一部として、XML Schemaを所有するデータベース・ユーザーの名前も指定します。ただし、XML Schema URLがOracle XML DBの名前空間に属している場合は除きます。
http://xmlns.oracle.com/xdb/schemas/<database-user>/<schemaURL-minus-protocol>
例8-11 完全修飾されたXML Schema URLの使用
たとえば、次のURLが設定されたグローバルXML Schemaについて考えてみます。
http://www.example.com/po.xsd
データベース・ユーザーQUINEが同じURLのローカルXML Schemaを所有していると想定します。
http://www.example.com/po.xsd
別のユーザーは、次のとおりQUINEが所有するローカルXML Schemaを参照できます。
http://xmlns.oracle.com/xdb/schemas/QUINE/www.example.com/po.xsd
同様に、グローバルXML Schemaの完全修飾されたURLは次のとおりです。
http://xmlns.oracle.com/xdb/schemas/PUBLIC/www.example.com/po.xsd
図8-2に示すとおり、複雑な要素に対するSQLTypeをキャラクタ・ラージ・オブジェクト(CLOB)値またはバイナリ・ラージ・オブジェクト(BLOB)値として指定できます。この場合、XMLフラグメント全体がLOB属性に格納されます。これは、XML文書に問合せがほとんど行われない部分があり、多くの場合、これらの部分の取出しおよび格納が個別に行われている場合に有効です。XMLフラグメントをLOBとして格納することによって、解析、分解および再組立てのオーバーヘッドを軽減できます。
例8-12 Oracle XML DBのXML Schema: LOBへのcomplexTypeのXMLフラグメントのマッピング
次の例では、XML Schemaによって、XMLフラグメントの要素Addrで属性SQLType = "CLOB"が使用されるように指定します。
DECLARE
doc VARCHAR2(3000) :=
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.oracle.com/emp.xsd"
xmlns:emp="http://www.oracle.com/emp.xsd"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<complexType name="Employee" xdb:SQLType="OBJ_T">
<sequence>
<element name="Name" type="string"/>
<element name="Age" type="decimal"/>
<element name="Addr" xdb:SQLType="CLOB">
<complexType >
<sequence>
<element name="Street" type="string"/>
<element name="City" type="string"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema('http://www.oracle.com/PO.xsd', doc);
END;
このXML Schemaを登録すると、Oracle XML DBによって、次の型およびXMLType表が生成されます。
CREATE TYPE obj_t AS OBJECT(SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
Name VARCHAR2(4000),
Age NUMBER,
Addr CLOB);
図8-2 キャラクタ・ラージ・オブジェクト(CLOB)へのcomplexTypeのXMLフラグメントのマッピング

XML Schemaでは、complexTypeの値はcomplexContentおよびsimpleContentに基づいて宣言されます。
simpleContentは、simpleTypeの拡張として宣言されます。
complexContentは、次のいずれかとして宣言されます。
ベース型
complexTypeの拡張
complexTypeの制限
この項では、Oracle XML DBのcomplexTypeに対する拡張および制限について説明します。
complexTypeの場合、次のとおりOracle XML DBによってXML Schemaで継承が処理されます。
他の複合型を拡張するように宣言された複合型の場合は、ベース型に対応するSQL型が、現在のSQL型のスーパータイプとして指定されます。サブcomplexTypeに宣言された追加属性および要素のみが、サブ・オブジェクト型に属性として追加されます。
他の複合型を制限するように宣言された複合型の場合は、サブcomplexTypeのSQL型がベース型のSQL型と同じになるように設定されます。これは、SQLでは継承メカニズムを介したオブジェクト型の制限がサポートされないためです。すべての制約は、XML Schemaでの制限によるものです。
例8-13 XML Schemaでの継承: complexTypeの拡張としてのcomplexContent
AddressというベースcomplexType、およびUSAddress、IntlAddressという2つの拡張を定義するXML Schemaについて考えてみます。
DECLARE
doc VARCHAR2(3000) :=
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<xs:complexType name="Address" xdb:SQLType="ADDR_T">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="USAddress" xdb:SQLType="USADDR_T">
<xs:complexContent>
<xs:extension base="Address">
<xs:sequence>
<xs:element name="zip" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="IntlAddress" final="#all" xdb:SQLType="INTLADDR_T">
<xs:complexContent>
<xs:extension base="Address">
<xs:sequence>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema('http://www.oracle.com/PO.xsd', doc);
END;
|
注意: 対応するcomplexTypeによってfinal属性が指定されるため、型intladdr_tはFINAL型として作成されます。デフォルトでは、すべてのcomplexTypeを他の型によって拡張および制限できるため、すべてのSQLオブジェクト型がFINALでない型として作成されます。 |
CREATE TYPE addr_t AS OBJECT(SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
"street" VARCHAR2(4000),
"city" VARCHAR2(4000)) NOT FINAL;
CREATE TYPE usaddr_t UNDER addr_t ("zip" VARCHAR2(4000)) NOT FINAL;
CREATE TYPE intladdr_t UNDER addr_t ("country" VARCHAR2(4000)) FINAL;
例8-14 XML Schemaでの継承: complexTypeの制限
ベースcomplexTypeのAddress、およびcountry属性を指定できないようにする制限型LocalAddressを定義するXML Schemaについて考えてみます。
DECLARE
doc varchar2(3000) :=
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<xs:complexType name="Address" xdb:SQLType="ADDR_T">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="zip" type="xs:string"/>
<xs:element name="country" type="xs:string" minOccurs="0"
maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="LocalAddress" xdb:SQLType="USADDR_T">
<xs:complexContent>
<xs:restriction base="Address">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="zip" type="xs:string"/>
<xs:element name="country" type="xs:string"
minOccurs="0" maxOccurs="0"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema('http://www.oracle.com/PO.xsd', doc);
END;
SQLでの継承は制限の概念がサポートされないため、制限されたcomplexTypeに対応するSQL型は、親オブジェクト型の空のサブタイプになります。前述のXML Schemaの場合、次のSQL型が生成されます。
CREATE TYPE addr_t AS OBJECT (SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
"street" VARCHAR2(4000),
"city" VARCHAR2(4000),
"zip" VARCHAR2(4000),
"country" VARCHAR2(4000)) NOT FINAL;
CREATE TYPE usaddr_t UNDER addr_t;
simpleContent宣言に基づくcomplexTypeは、XML属性に対応する属性および本体の値に対応する追加のSYS_XDBBODY$属性を持つオブジェクト型にマップされます。本体属性のデータ型は、本体の型を定義するsimpleTypeに基づきます。
例8-15 XML SchemaのcomplexType: simpleContentへのcomplexTypeのマッピング
DECLARE
doc VARCHAR2(3000) :=
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.oracle.com/emp.xsd"
xmlns:emp="http://www.oracle.com/emp.xsd"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<complexType name="name" xdb:SQLType="OBJ_T">
<simpleContent>
<restriction base="string">
</restriction>
</simpleContent>
</complexType>
</schema>';
BEGIN
DBMS_XMLSCHEMA.registerschema('http://www.oracle.com/emp.xsd', doc);
END;
このXML Schemaを登録すると、Oracle XML DBによって、次の型およびXMLType表が生成されます。
CREATE TYPE obj_t AS OBJECT(SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
SYS_XDBBODY$ VARCHAR2(4000));
Oracle XML DBでは、要素の宣言であるanyおよび属性の宣言であるanyAttributeは、作成されたオブジェクト型のVARCHAR2属性(またはオプションでラージ・オブジェクト(LOB))にマップされます。オブジェクト属性によって、any宣言に一致するXMLフラグメントのテキストが格納されます。
コンテンツが指定された名前空間に属するように、namespace属性を使用してコンテンツを制限できます。
any要素宣言内のprocessContents属性は、any宣言に一致するコンテンツに必要な検証レベルを示します。
例8-16 Oracle XML DBのXML Schema: any/anyAttributeへのcomplexTypeのマッピング
このXML Schemaの例では、any要素が宣言され、オブジェクト型obj_tの列SYS_XDBANY$にそれがマップされます。また、この要素によって、processContents属性がany宣言に一致する検証対象のコンテンツをスキップすることが宣言されます。
DECLARE
doc VARCHAR2(3000) :=
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.oracle.com/any.xsd"
xmlns:emp="http://www.oracle.com/any.xsd"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<complexType name="Employee" xdb:SQLType="OBJ_T">
<sequence>
<element name="Name" type="string"/>
<element name="Age" type="decimal"/>
<any namespace="http://www/w3.org/2001/xhtml"
processContents="skip"/>
</sequence>
</complexType>
</schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema('http://www.oracle.com/emp.xsd', doc);
END;
これによって、次の文が生成されます。
CREATE TYPE obj_t AS OBJECT(SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
Name VARCHAR2(4000),
Age NUMBER,
SYS_XDBANY$ VARCHAR2(4000));
Oracle XML DBは、XML Schemaに基づくデータをサポートしています。このようなデータでは、要素および属性にXML Schemaの型情報が関連付けられています。しかし、XPath 1.0ではデータ型の情報が認識されません。Oracle XML DBはXPath 1.0を拡張し、データ型情報の調査をサポートするための次のOracle関数を備えています。
instanceof
instanceof-only
これらのXPath関数は名前空間http://xmlns.oracle.com/xdbにあり、事前定義された接頭辞oraが付いています。
要素の型が指定の型と同じ場合、または指定の型のサブタイプである場合、その要素は、指定されているXML Schemaデータ型のインスタンスです。XML Schemaのコンテキストにある型Tのサブタイプは、Tを拡張または制限する型、またはTの別のサブタイプを拡張または制限する型です。
XML Schemaに基づくデータが含まれたXPath式の場合、結果セットを特定のデータ型のノードに制限するには、Oracle XPath関数ora:instanceof-onlyを使用します。また、結果セットを特定のデータ型またはそのサブタイプのノードに制限するには、ora:instanceofを使用します。XML Schemaに基づかないXMLデータの場合、要素および属性はデータ型情報を持ちません。このため、XML Schemaに基づかないデータに対しては、これらの関数はfalseを戻します。
構文
ora:instanceof-only(nodeset-expr, typename [, schema-url])
XML Schemaに基づくデータの場合、ora:instanceof-onlyは、XPath式nodeset-exprを評価し、結果として戻される各ノードのXML Schemaデータ型を判断します。式nodeset-exprは、通常、相対的なXPath式になります。ノードのいずれかのデータ型がデータ型typename(文字列)と完全に一致する場合(名前空間の接頭辞で修飾されている場合があります)、instanceof-onlyはtrueを戻します。それ以外の場合は、falseを戻します。XML Schemaに基づかないデータの場合、falseを戻します。
オプションのパラメータschema-url(文字列)は、一致するデータ型のスキーマの場所を示すURLを示します。指定する場合、schema-urlパラメータは、ノードのデータ型を定義するXML Schemaの場所を指定している必要があります。schema-urlパラメータが指定されていない場合、ノードのスキーマの場所はチェックされません。
構文
ora:instanceof(nodeset-expr, typename [, schema-url])
Oracle XPath関数ora:instanceofはora:instanceof-onlyと似ていますが、一致するノードのいずれかのデータ型がデータ型typenameのサブタイプに完全に一致する場合も、trueを戻します。
例8-18 ora:instanceofの使用
次の問合せは、データ型がPersonTypeまたはそのサブタイプの1つである要素Personの子AEのName属性を選択します。
SELECT extract(OBJECT_VALUE,
'/p9:Person[ora:instanceof(AE, "p9:PersonType")]/AE/Name',
'xmlns:p9="person9.xsd" xmlns:ora="http://xmlns.oracle.com/xdb"')
FROM po_table;
スキーマの場所を示すパラメータは、通常、異機種間のXML Schemaシナリオで使用されます。異機種間のXML Schemaに基づくデータは単一の表で表すことができます。XML Schemaに基づく表に関連した例の場合は、スキーマの場所を示すパラメータの省略を考慮します。
XMLTypeのXML Schemaに基づかない表を考えてみます。表の各行は、XML文書です。各行に、XML Schema情報が指定されているデータが含まれていると仮定します。後続の操作によって、表のデータがXML Schemaに基づくデータに変換された場合、その表の行は異なるXML Schemaに関連付けられている可能性があります。このような場合は、データ型が一致する名前および名前空間に加え、スキーマの場所を示すURLも指定できます。
例8-19 異機種間のXML Schemaに基づくデータでのora:instanceofの使用
次の問合せは、XML Schemaに基づかない表non_sch_p_tabで、XML Schemaperson9.xsdに関連する型PersonTypeの要素を照合します。
SELECT extract(
createSchemaBased(
OBJECT_VALUE),
'/p9:Person/AE[ora:instanceof(.,"p9:PersonType", "person9.xsd")]',
'xmlns:p9="person9.xsd" xmlns:ora="http://xmlns.oracle.com/xdb"')
FROM non_sch_p_tab;
W3C XML Schema勧告では、complexTypesおよびグローバル要素に再帰的参照を挿入できます。たとえば、complexType定義にその同じcomplexTypeに基づく要素を含めたり、グローバル要素に自己参照を含めることができます。いずれの場合も、直接または間接的な参照にできます。この種の構造では、対象の要素が再帰的階層で無限に出現する可能性があるインスタンス・ドキュメントを使用できます。
例8-20 循環依存を使用したXML Schema
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="person" type="personType" xdb:defaultTable="PERSON_TABLE"/>
<xs:complexType name="personType" xdb:SQLType="PERSON_T">
<xs:sequence>
<xs:element name="descendant" type="personType" minOccurs="0"
maxOccurs="unbounded" xdb:SQLName="DESCENDANT"
xdb:defaultTable="DESCENDANT_TABLE"/>
</xs:sequence>
<xs:attribute name="personName" use="required" xdb:SQLName="PERSON_NAME">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:schema>
例8-20のXML Schemaには、循環依存が含まれています。complexType personTypeは、personName属性およびdescendant要素のコレクションで構成されます。descendant要素は、personTypeの実体として定義されます。
Oracle XML DBでは、この種の構造を定義するXML Schemaをサポートしています。循環を検出して使用不可にし、XML Schema登録時に作成された別々のXMLType表に再帰的要素を行として格納することで、このサポートを実現しています。
したがって、この種の構造を定義するXML Schemaを登録する場合は、パラメータgenTablesがTRUEに設定されていることが重要です。再帰的要素の格納に使用する表の名前は、XML Schemaにxdb:defaultTable注釈を追加することで指定できます。
SQLオブジェクト型では、循環を使用できません。オブジェクト型の生成時、循環が完了した時点でREF属性を設定することによって、XML Schemaでの循環が使用不可になります。このように、データの一部は表外に格納されていても、親であるXML文書の一部として取得されます。
例8-21 XML Schema: complexType間での循環
XML Schemaでは、complexTypeの定義間に循環を設定できます。図8-3にこの例を示します。complexType CT1の定義は別のcomplexType CT2を参照でき、CT2の定義は最初の型CT1を参照します。
XML Schemaでは、complexTypeの定義間に循環を設定できます。長さが2の循環の例を示します。
DECLARE
doc VARCHAR2(3000) :=
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<xs:complexType name="CT1" xdb:SQLType="CT1">
<xs:sequence>
<xs:element name="e1" type="xs:string"/>
<xs:element name="e2" type="CT2"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CT2" xdb:SQLType="CT2">
<xs:sequence>
<xs:element name="e1" type="xs:string"/>
<xs:element name="e2" type="CT1"/>
</xs:sequence>
</xs:complexType>
</xs:schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema('http://www.oracle.com/emp.xsd', doc);
END;
SQL型では、型の定義で循環を使用できません。ただし、REF(参照)属性を伴う循環など、弱い循環はサポートされます。必要に応じて強制的にSQLInline="false"を設定することで循環を回避し、循環するXML Schema定義はSQLオブジェクト型にマップされます。これによって、弱いSQL循環が作成されます。
前述のXML Schemaの場合、次のSQL型が生成されます。
CREATE TYPE ct1 AS OBJECT (SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
"e1" VARCHAR2(4000),
"e2" REF XMLType) NOT FINAL;
CREATE TYPE ct2 AS OBJECT (SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
"e1" VARCHAR2(4000),
"e2" CT1) NOT FINAL;
例8-22 XML Schema: complexType間での循環、自己参照
循環するcomplexTypeに、自己参照するcomplexTypeの宣言が含まれる場合があります。この例では、型<SectionT>は自己参照しています。
DECLARE
doc VARCHAR2(3000) :=
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<xs:complexType name="SectionT" xdb:SQLType="SECTION_T">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:choice maxOccurs="unbounded">
<xs:element name="body" type="xs:string"
xdb:SQLCollType="BODY_COLL"/>
<xs:element name="section" type="SectionT"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:schema>';
BEGIN
DBMS_XMLSCHEMA.registerSchema('http://www.oracle.com/section.xsd', doc);
END;
次のSQL型が生成されます。
CREATE TYPE body_coll AS VARRAY(32767) OF VARCHAR2(4000);
CREATE TYPE section_t AS OBJECT (SYS_XDBPD$ XDB.XDB$RAW_LIST_T,
"title" VARCHAR2(4000),
"body" BODY_COLL,
"section" XDB.XDB$REF_LIST_T) NOT FINAL;
|
注意: section属性は、XMLTypeインスタンスに対するREF参照のVARRAYとして宣言されます。複数の埋込みセクションが出現する場合があるため、属性はVARRAYになります。また、SQLオブジェクトの循環が構成されないようにするためにも、属性はXMLTypeインスタンスに対するREF参照のVARRAYになります。 |
http://www.oracle.com/PO.xsdによって識別されるXML Schemaが登録されているとします。この場合、XMLType表のmyPOsを作成し、このXML Schemaの要素PurchaseOrderに準拠するインスタンスをオブジェクト・リレーショナル形式で格納できます。
CREATE TABLE purchaseorder OF XMLType ELEMENT "http://www.oracle.com/PO.xsd#PurchaseOrder";
図8-4に、スキーマでのcomplexTypeの自己参照の方法を示します。
PurchaseOrder要素がマップされているオブジェクト型に対応する、非表示の列が作成されます。また、名前空間宣言など、最上位インスタンスのデータを格納するためのXMLExtraオブジェクト列が作成されます。
XML Schemaどうしを、通常の方法で逐次的に登録できないように、相互に依存させることができます。そのようなXML Schemaの説明を図8-5に示します。
図の上半分は、3つのXML Schema間の間接循環参照の例を示しています。
図の下半分は、2つのXML Schema間の循環依存の例を示しています。この簡単な例の詳細を次に説明します。
例8-23 循環型の依存性
他のXML Schemaを含むXML Schemaは、その含まれるXML Schemaが存在しない場合には作成できません。
BEGIN DBMS_XMLSCHEMA.registerSchema(
'xm40.xsd',
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:my="xm40"
targetNamespace="xm40">
<include schemaLocation="xm40a.xsd"/>
<!-- Define a global complextype here -->
<complexType name="Company">
<sequence>
<element name="Name" type="string"/>
<element name="Address" type="string"/>
</sequence>
</complexType>
<!-- Define a global element depending on included schema -->
<element name="Emp" type="my:Employee"/>
</schema>',
TRUE,
TRUE,
FALSE,
TRUE);
END;
/
ただし、FORCE => TRUEオプション(最後の引数)を使用すると作成できます。
BEGIN DBMS_XMLSCHEMA.registerSchema(
'xm40.xsd',
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:my="xm40"
targetNamespace="xm40">
<include schemaLocation="xm40a.xsd"/>
<!-- Define a global complextype here -->
<complexType name="Company">
<sequence>
<element name="Name" type="string"/>
<element name="Address" type="string"/>
</sequence>
</complexType>
<!-- Define a global element depending on included schema -->
<element name="Emp" type="my:Employee"/>
</schema>',
TRUE,
TRUE,
FALSE,
TRUE,
TRUE);
END;
/
このスキーマを使用して、再コンパイルを実行しようとすると失敗します。
CREATE TABLE foo OF XMLType XMLSCHEMA "xm40.xsd" ELEMENT "Emp";
FORCEオプションを使用して、2つ目のXML Schemaを作成します。これによって、最初のXML Schemaも有効になります。
BEGIN DBMS_XMLSCHEMA.registerSchema(
'xm40a.xsd',
'<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:my="xm40"
targetNamespace="xm40">
<include schemaLocation="xm40.xsd"/>
<!-- Define a global complextype here -->
<complexType name="Employee">
<sequence>
<element name="Name" type="string"/>
<element name="Age" type="positiveInteger"/>
<element name="Phone" type="string"/>
</sequence>
</complexType>
<!-- Define a global element depending on included schema -->
<element name="Comp" type="my:Company"/>
</schema>',
TRUE,
TRUE,
FALSE,
TRUE,
TRUE);
END;
/
表の作成には、それぞれのXML Schemaを使用できます。
CREATE TABLE foo OF XMLType XMLSCHEMA "xm40.xsd" ELEMENT "Emp"; CREATE TABLE foo2 OF XMLType XMLSCHEMA "xm40a.xsd" ELEMENT "Comp";
相互に依存するこれらのXML Schemaを両方とも登録するには、次のとおりDBMS_XMLSCHEMA.registerSchemaでFORCEパラメータを使用する必要があります。
xm40.xsdを、FORCEモードをTRUEに設定して登録します。
DBMS_XMLSCHEMA.registerSchema("xm40.xsd", "<schema ...", ..., FORCE => TRUE)
この時点では、xm40.xsdは無効で使用できません。
xm40a.xsdを、FORCEモードをTRUEに設定して登録します。
DBMS_XMLSCHEMA.registerSchema("xm40a.xsd", "<schema ...", ..., FORCE => TRUE)
これによってxm40.xsdが自動的にコンパイルされ、両方のXML Schemaが有効になります。
REFを表外の表に含まれる再帰的構造に格納すると、コンパイル時に構造の階層の深さがわからないので、そのようなドキュメントに対するXPath問合せが簡単にリライトできないというデメリットがあります。そのようなXPath問合せのリライトを有効にするには、すべての再帰的構造でDOCID列を使用してルート・ドキュメントへのポインタを格納します。これにより、問合せが表外の表を直接使用し、この列を使用して後戻り結合ができます。次のスキーマを考えてみます。
例8-24 再帰的スキーマ
<schema targetNamespace="AbcNS" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:abc="AbcNS" xmlnm:xdb="http://xmlns.oracle.com.xdb">
<element name="AbcCode" xdb:defaultTable="ABCCODETAB">
<complexType>
<sequence>
<element ref="abc:AbcSection"/>
</sequence>
</complexType>
</element>
<element name="AbcSection">
<complexType>
<sequence>
<element name="ID" type="integer"/>
<element name="Contents" type="string"/>
<element ref="abc:AbcSection"/>
</sequence>
</complexType>
</element>
</schema>
文書が相互に関連する再帰的な問合せは、'//'を含むXPath式またはXQuery式、およびXMLTypeインスタンスを受け入れるSQL関数を使用する問合せです。文書が相互に関連する再帰的な問合せは、次の条件の両方を満たすことが問合せのコンパイル時に決定できる場合は、リライトできます。
XPath式またはXQuery式のターゲットとなるXMLTypeインスタンスのすべてのフラグメントが単一の表外の表に存在すること。
XMLTypeインスタンスの他のフラグメントが同じ表外の表に存在しないこと。
リライトされた問合せは、DOCID列に基づいて表外の表と結合されます。
'//'を持つその他の問合せもリライトできます。たとえば、スキーマの異なるセクションにある、すべて同じ型のaddress要素がいくつかある場合に、ドキュメント内の場所を特定せずに'//'を持つすべてのaddress要素を頻繁に問合せする場合は、リライトが発生する可能性があります。
スキーマ登録時に、追加のDOCID列が表外のXMLType表に生成されます。この列は、ドキュメントのOID(オブジェクト識別子の値)、つまりルート要素を格納します。この列は、データが表に挿入されると自動的に移入されます。DOCID列を含む表をエクスポートし、後でそれらをインポートできます。
同じ修飾名(名前空間およびローカル名)と同じ型の表外の要素は、同じデフォルト表に格納されます。特殊な場合として、ユーザーは循環型要素構造のルート要素も表外およびサブ要素と同じ表の中に格納できます(ルート要素も表外に格納されている場合)。
デフォルト表を共有している要素は両方とも表外の要素である必要があります。つまり、ある表外の要素に対するデフォルト表は、最上位要素に対する表と同じにできません。同じにするには、両方の要素にxdb:SQLInline ='FALSE"を指定し、同じ値を持つ明示的なxdb:defaultTable属性を両方の要素の中で指定します。
表外の表がABCSECTIONTABに格納されている例を考えてみます。
例8-25 表外の表
<schema targetNamespace="AbcNS" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:abc="AbcNS" xmlns:xdb="http://xmlns.oracle.com/xdb">
<element name="AbcCode" xdb:defaultTable="ABCCODETAB">
<complexType>
<sequence>
<element ref="abc:AbcSection" xdb:SQLInline="false"/>
</sequence>
</complexType>
</element>
<element name="AbcSection" xdb:defaultTable="">
<complexType>
<sequence>
<element name="ID" type="integer"/>
<element name="Contents" type="string"/>
<element ref="abc:AbcSection" xdb:SQLInline="false"
xdb:defaultTable="ABCSECTIONTAB"/>
</sequence>
</complexType>
</element>
</schema>
前述の例の表外のAbcSection要素は、両方とも同じデフォルト表ABCSECTIONTABを共有しています。
ただし、次の例は、デフォルト表の無効な共有を示しており、再帰的要素(XyZSection)は同じ表外の表を共有しません。
例8-26 デフォルト表の無効な共有
<schema targetNamespace="XyzNS" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xyz="XyzNS" xmlns:xdb="http://xmlns.oracle.com/xdb">
<element name="XyzCode" xdb:defaultTable="XYZCODETAB">
<complexType>
<sequence>
<element name="CodeNumber" type="integer" minOccurs="0"/>
<element ref="xyz:XyzChapter" xdb:SQLInline="false"/>
<element ref="xyz:XyzPara" xdb:SQLInline="false" />
</sequence>
</complexType>
</element>
<element name="XyzChapter" xdb:defaultTable="XYZCHAPTAB">
<complexType>
<sequence>
<element name="Title" type="string"/>
<element ref="xyz:XyzSection" xdb:SQLInline="false"
xdb:defaultTable="XYZSECTIONTAB"/>
</sequence>
</complexType>
</element>
<element name="XyzPara" xdb:defaultTable="XYZPARATAB">
<complexType>
<sequence>
<element name="Title" type="string"/>
<element ref="xyz:XyzSection" xdb:SQLInline="false"
xdb:defaultTable="Other_XYZSECTIONTAB"/>
</sequence>
</complexType>
</element>
<element name="XyzSection">
<complexType>
<sequence>
<element name="ID" type="integer"/>
<element name="Contents" type="string"/>
<element ref="xyz:XyzSection" xdb:defaultTable="XYZSECTIONTAB"/>
</sequence>
</complexType>
</element>
</schema>
次の問合せはリライトできません。
SELECT extract(value(p), '//XyzSection') FROM xyzcode p;
// XPath式を処理する前に、同じ要素が複数回出現していないか確認します。//の下にあるすべての出現が同じdefaultTableを共有する場合、DOCIDを使用した表に対して問合せをリライトできます。//の下ではなく、その表を共有しているルートの下に、同じ要素の出現が他にある場合、問合せはリライトできません。たとえば、次の要素構造を考えます。
<Book>が<Chapter>および<Part>を含む。<Part>が<Chapter>を含む。
両方の<Chapter>要素が表外に格納されており、同じデフォルト表を共有しているとします。/Book//Chapterという問合せは、<Book>の下にあるすべての<Chapter>要素は同じデフォルト表を共有するので、<Chapter>要素のデフォルト表に対してリライトできます。このため、このXPath問合せは、文書が相互に関連する再帰的なXPath問合せです。
ただし、<Part>の下にあるすべての<Chapter>要素が同じ表を共有している場合でも、/Book/Part//Chapterのような問合せはリライトできません。その理由は、<Book>(同様にその表を共有しているドキュメント・ルート)の下に別の<Chapter>があるからです。
例8-25のXML Schemaで説明したように、DOCIDが存在する状況で//AbcSectionの抽出を行う場合を考えます。
SELECT extract(value(x), '//AbcSection') FROM abccodetab;
両方のAbcSection要素が、同じ表abcsectiontabに格納されています。抽出は、基礎となるabcsectiontab表に対して行われます。
DOCIDが存在する状況で次の問合せを考えます。
SELECT extract(value(x), '/AbcCode/AbcSection//AbcSection') FROM abccodetab;
前述の例とこの例の両方で、アクセス可能なすべてのAbcSection要素が同じ表外の表に格納されています。ただし、/AbcCode/AbcSectionにある最初のAbcSection要素は、この問合せでは取得できません。結合条件は、親ドキュメント内の異なる位置を区別できないDOCIDなので、表abcsectiontabに対する直接の問合せでは正しい結果が得られません。この場合、文書が相互に関連する再帰的なXPathではないので、問合せのリライトは発生しません。この最上位のAbcSectionがその他とともに表外に格納されていない場合、問合せをリライトできます。
DBMS_XMLSCHEMA.registerSchemaを呼び出す際、そのプロシージャのオプションの最後のパラメータを指定することで、DOCID列の作成を無効化できます。これにより、スキーマ登録時に生成されるすべてのXMLType表でDOCIDの作成が無効化されます。registerSchemaプロシージャのパラメータは次のとおりです。
PROCEDURE registerSchema(
SCHEMAURL IN VARCHAR2,
SCHEMADOC IN VARCHAR2,
LOCAL IN BOOLEAN := TRUE,
GENTYPES IN BOOLEAN := TRUE,
GENBEAN IN BOOLEAN := FALSE,
GENTABLES IN BOOLEAN := TRUE,
FORCE IN BOOLEAN := FALSE,
OWNER IN VARCHAR2 := '',
OPTIONS IN pls_integer := 0);
DOCID列が生成されないようにするには、optionsパラメータを次のように設定します。
DBMS_XMLSCHEMA.REGISTER_NODOCID
|
関連項目: 『Oracle Database PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』 |
この項では、Oracle XML DBでXML Schemaを使用する場合のガイドラインについて説明します。
バインド変数を使用すると、Oracle Databaseによって、文字列リテラル値のかわりにバインド変数が使用されている箇所について問合せがリライトされます。また、Oracle Databaseですべての文字列式に対して常にバインド変数が使用されるように、CURSOR_SHARINGをFORCEに設定することもできます。
バインド変数を使用したXPathリライト
XPathでバインド変数が文字列リテラルとして使用されている場合は、そのバインド変数を使用するように式をリライトできます。連結演算子(||)を使用した文字列リテラルのかわりにバインド変数を使用し、XPath文字列内のバインド変数は一重(')または二重(")引用符で囲む必要があります。次に、XPathリライトでのバインド変数の使用例を示します。
例8-27 XPathでのバインド変数の使用
BEGIN
DBMS_XMLSCHEMA.registerschema(
'bindtest.xsd',
'<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xdb="http://xmlns.oracle.com/xdb">
<xs:element name="Employee" xdb:SQLType="EMP_BIND_TYPE">
<xs:complexType>
<xs:sequence>
<xs:element name="EmployeeId" type="xs:positiveInteger"/>
<xs:element name="PhoneNumber" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>',
TRUE,
TRUE,
FALSE,
FALSE);
END;
/
-- Create table corresponding to the Employee element
CREATE TABLE emp_bind_tab OF XMLType
ELEMENT "bindtest.xsd#Employee";
-- Create an index to illustrate the use of bind variables
CREATE INDEX employeeId_idx ON emp_bind_tab
(extractValue(OBJECT_VALUE, '/Employee/EmployeeId'));
EXPLAIN PLAN FOR
SELECT extractValue(OBJECT_VALUE, '/Employee/PhoneNumber')
FROM emp_bind_tab
WHERE existsNode(OBJECT_VALUE, '/Employee[EmployeeId="'||:1||'"] ') = 1;
SELECT PLAN_TABLE_OUTPUT
FROM table(DBMS_XPLAN.display('plan_table', NULL, 'serial'))/
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------
| Id | Operation | Name |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP_BIND_TAB |
|* 2 | INDEX RANGE SCAN | EMPLOYEEID_IDX |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("SYS_ALIAS_1"."SYS_NC00008$"=TO_NUMBER(:1))
バインド変数:1は、二重引用符(")で囲まれた文字列リテラル値として使用されます。これによって、Oracle XML DBによるXPath式'/Employee[EmployeeId=" ' || :1 || ']'のリライトが可能になり、オプティマイザでは、述語を満たすためにEmployeeId_idx索引を使用できます。
XPathリライトでは、Oracle Databaseによって、入力されたXPath式が基礎となる列を使用するように変更されます。つまり、指定されたXPathには、内部的に参照される列や表の特定のセットが存在します。参照する表と列は共有カーソルによって正確に認識される必要があるため、XPath式の変更はコンパイル時の操作であることが必要です。各行、またはカーソルの各インスタンスに対して異なる参照先を使用することはできません。
このため、XPath式自体がバインド変数である場合、カーソルのインスタンス化ごとにまったく異なるXPath式が使用される可能性があるため、Oracle Databaseはリライトを行うことができません。これは、SQL問合せで列または表の名前をバインドする場合に類似しています。たとえば、SELECT * FROM table(:1)などです。
|
注意: バインド変数は、問合せの右側に指定できます。たとえば、この問合せでは通常のバインド変数の共有が使用されています。
SELECT * FROM purchaseorder
WHERE extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference')
= :1;
|
CURSOR_SHARINGがFORCEに設定されている場合は、XPathを含む各文字列の定数がデフォルトでバインド変数になります。Oracle Databaseでは、SQL関数extractvalueやexistsnodeなどを検出すると、XPathバインド変数を参照して、それらが実際の定数であるかどうかを確認します。定数の場合は、その定数を使用してクエリーをリライトします。このように、バインド変数の使用方法によって大きな差異があります。
構成ファイル/xdbconfig.xmlには、ロード操作で使用されるメモリー量を制御するパラメータがあります。これにより、次の条件が満たされた場合は、ロード処理を最適化できます。
文書が、プロトコル(FTP、HTTP(S)またはDAV)を介して、またはPL/SQL関数DBMS_XDB.createResourceを介してロードされていること。
文書がXML Schemaに基づいており、大規模なコレクション(maxoccursが大きな数に設定されている要素)を含んでいること。
文書のコレクションはOCTとして格納されていること。これがデフォルトの動作です。
これらの最適化は、実表にトリガーがない場合に最も有用であること。トリガーが出現する状況では、パフォーマンスは部分的な最適化となる可能性があります。
この最適化の背景にある基本概念は、最適化によって、メモリーとの間で行うコレクションのスワップを、限定されたサイズで可能にすることです。この概念を示すために、発注書XML Schemaに準拠した次の例を考えてみます。
<PurchaseOrder>
<LineItem itemID="1">
...
</LineItem>
.
.
<LineItem itemID="10240">
...
</LineItem>
</PurchaseOrder>
この発注書文書には、10240のLineItem要素のコレクションが含まれています。文書全体をメモリー内に作成してからディスクにプッシュする(この処理は結果的に過度なメモリー使用となり、一部のインスタンスではシステム・メモリー不足のためにロードに障害が発生します)かわりに、ロード可能ユニットと呼ばれる限定されたメモリー・チャンクに文書を作成します。この例の場合、各明細項目には1KBのメモリーを必要とし、512KBのロード可能ユニット・サイズを使用すると仮定した場合、各ロード可能ユニットには、512項目の明細が含まれ、このようなユニットが約20ユニット存在することになります。さらに、ドキュメントのメモリー表現全体を常に2MB以下のサイズにする必要がある場合は、メモリー内に保持されるロード可能ユニットがいつでも4ユニット以下となるようにできます。LRUメカニズムを使用して、ロード可能ユニットをスワップ・アウトします。
ロード可能ユニットのサイズおよび文書サイズの限度を制御することで、ロードまたは取得時のメモリー使用とパフォーマンスを調整できます。一般に、ロード可能ユニット・サイズが大きいほど、ディスク・アクセス回数は少なくなりますが、メモリー所要量は大きくなります。ロード可能ユニットのサイズは、xdbcore-loadableunit-sizeパラメータで制御されます。デフォルト値は16KBです。文書に割り当てるメモリー量は、xdbcore-xobmem-boundパラメータで指定できます。デフォルト値は1MBです。これらのパラメータの値は、KBで指定します。つまり、xdbcore-xobmem-boundのデフォルト値は1024で、xdbcore-loadableunit-sizeのデフォルト値は16です。これらはメモリーを最適に使用する方法に関する指示をシステムに示すソフトな制限です。
前述の例で、文書のFTPロードを実行すると、ロード可能ユニット(LU)が作成され、ディスクにフラッシュされるパターンは、次のとおりです。
No LUs Create LU1[LineItems(LI):1-512] LU1[LI:1-512], Create LU2[LI:513-1024].. LU1[LI:1-512],...,Create LU4[LI:1517:2028] <- Total memory size = 2M Swap Out LU1[LI:1-512], LU2[LI:513-1024],...,LU4[LI:1517-2028], Create LU5[LI:2029-2540] Swap Out LU2[LI:513-1024], LU3, LU4, LU5, Create LU6[LI:2541-2052]... Swap Out LU16, LU17, LU18, LU10, Create LU20[LI:9729-10240] Flush LU17,LU18,LU19,LU20
一般に、アドレス指定可能なPGAが1GBある場合は、PGAの10分の1を文書に割り当てます。つまり、アドレス指定可能なPGAが100MBある場合は、その10分の1をxobcore-xobmem-boundに設定します。文書の完全な取得およびロードでは、xdbcore-loadableunit-sizeを、あるエラーの範囲内で、xobcore-xobmem-boundのサイズにできるかぎり近づけてください。ただし、実際にはxdbcore-xobmem-boundの半分の値を設定します。この場合は50MBです。この値から文書のロードの試行を開始します。メモリー不足になった場合は、xdbcore-xobmem-boundの値を減らし、xdbcore-loadableunot-sizeをその半分の値に設定し、文書がロードされるまでこの作業を繰り返します。ロードが正常に完了した場合は、xdbcore-loadableunit-sizeの値を増やし、よりよいパフォーマンスを引き出せるかどうかを確認します。xdbcore-loadableunit-sizeがxdbcore-xobmem-boundと等しい場合は、さらにパフォーマンスを向上させるために両方のパラメータを大きくします。