この章では、構造化された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
と等しい場合は、さらにパフォーマンスを向上させるために両方のパラメータを大きくします。