DBA:内容管理
   下载
 Oracle 数据库 11g
 
   标签
xml, 11g, 全部
 

 

在 Oracle XML DB 11g 中管理复杂的 XML 数据


作者:V.J. Jain

 

了解如何使用 Oracle XML DB 11g 管理复杂的 XML,包括如何联机更改模式

2007 年 12 月发布

在过去几年里,XML 已经成为数据传输的新标准,随着企业不断采用基于 XML 的解决方案,其应用也越来越普遍。随着更多组织对所有数据传输执行 XML 标准,日益复杂的 XML 格式不断出现。这些复杂的格式可以包括多个命名空间、数千个元素和递归定义。随着这些格式所生成的 XML 文档的大小和复杂性的不断增加,管理这些内容变得越来越具有挑战性,而有关应对这些挑战的信息却极为有限。

在本文中,您将了解如何使用 Oracle 数据库 11g 中的 XML DB 特性管理复杂的 XML 内容,以及与商用 ETL 产品相比它所具有的优势。您将看到一个用于演示下述内容的复杂 XML 模式的示例:

  • 注册复杂的 XML 模式
  • 将 XML 文件插入到数据库中
  • 通过关系查询检索 XML 数据
  • XML 模式修改的原地演变
此外,您还可以大致了解使得 Oracle XML DB 解决方案的性能和吞吐量最大化的策略以及复杂 XML 格式的实际应用。

Oracle XML DB 的背景

Oracle XML DB 是 Oracle 数据库的一个特性,它提供了一个用于管理 XML 内容的强大工具,包括存储、操作和检索。它提供不同的存储选项,以满足不同 XML 格式的独特要求。这些选项包括非结构化、二进制和结构化存储:

  • 非结构化(字符大对象,即 CLOB)。通过将文档作为一个大对象并将其插入到数据库中,此方法可获得最佳插入次数。然而,对于数据的关系访问而言,此存储方法消耗的空间最大且性能最差。如果需要采用关系访问,这不是一个管理大型复杂 XML 文档的实用解决方案。如果磁盘空间不是问题且目标以文档的原始格式对其进行存储,非结构化存储是一个实用的解决方案。
  • 二进制存储。 这是 Oracle 数据库 11g 中的一个新增选项,以专门针对 XML 数据设计的分析后的二进制格式来存储数据。该选项与非结构化存储相比有许多优势,它可以感知 XML 模式,从而可以获得更高的磁盘空间效率和查询性能。尽管该选项可以提供非结构化存储无法比拟的性能,但它的查询性能却逊色于结构化存储。只要可以接受二进制存储在关系访问时的性能,它就是一个很好的选项。由于该存储选项易于使用,因此在选择结构化存储前值得对其进行评价。
  • 结构化存储。 也称作基于模式的存储,该选项使用对象关系模型在数据库中存储 XML 文档。此存储选项在磁盘空间和关系访问方面效率最高。它在文件插入时的开销也是最高的,要求为模式注册进行额外的准备。在要求最佳关系访问时,结构化存储是最佳选项。在处理复杂的大文件并要求高效的关系访问时,该存储选项通常是最好的选择。
不同组织对 XML 文档的大小和复杂性的看法可能迥然不同。一方面,对于使用 XML 进行电子数据交换 (EDI) 或其他事务数据交换的联机事务处理 (OLTP) 数据库而言,具有有数千行的文件会被视为一个非常大的文件。另一方面,一个多 TB 的数据仓库可能经常处理以 GB 计的 XML 文档,因此只将包含数百万行的文件看作大文件。对于 XML 文档复杂性的看法,这一概念同样适用。

就本文而言,具有以下属性的文档被看作是一个“复杂”文档:

  • 具有单根节点和多个命名空间的文档。
  • 具有灵活的 XML 定义、在维持有效性的同时允许较大变化的文档。
  • 具有递归或循环引用的文档。
  • 具有非静态 XML 模式的文档。
在本文中,如果 XML 文档是单根节点且大于 20MB,就被看作“大型文档”。这些属性介绍了一个强健的企业解决方案所必须解决的可伸缩性和管理问题。

在最佳存储选项的选择上,没有什么金科玉律。最佳选项将随文件结构、性能目标、可用资源和预期数据量的变化而变化。如果您无法确定哪个存储选项最符合您的特定需求,不妨试试不同的格式再确定最符合您特定需求的最佳选项。一般而言,如果您要处理大型文档并且需要进行关系访问,非结构化存储从性能或资源角度是不可接受的。如果查询性能可以为业务使用所接受或者业务需要维护时间最短的选项,二进制 XML 可能是最佳解决方案。然而,如果关系访问是主要目标,并且用户需要快速访问 XML 文档中包含的任何数据,结构化存储最有可能是最佳选项。

使用结构化存储使吞吐量达到最大

虽然使用结构化存储选项时存在因插入文件所导致的开销成本,但是您可以通过将大文档分解成多个小文档来减少这一开销。例如,如果有一个 700MB 的单根节点的 XML 文件,可以将它分解为 10 个 XML 模式有效的小文件。插入 10 个不同的 70MB 文件要比插入一个 700MB 的文件快得多,但最终结果相同。并发级别应由数据库的可用处理能力决定。该策略利用了数据库并发性,并且使吞吐量达到最大。

使用 Oracle XML DB 时的另一个考虑事项是,单个 XML 文件的插入时间通常受单个 CPU 速度的限制。换言之,拥有多个处理器对于单个文档的吞吐量没什么帮助。例如,考虑这一情况,一个复杂的、单根节点的 700MB 文档需要使用基于模式的存储进行插入。使用 1.35GHz 的处理器时,无论数据库有 12 个还是 72 个 CPU (假定任何情形下至少有一个 CPU 可用),插入该文件所用的总时间可能是 10 分钟。要提高单个 XML 文档的吞吐量,您可能需要使用更快的 CPU。使用 3.4GHz 的处理器时,插入同一个文件可能需要 4 分钟。相反地,当您处理多个 XML 文件时,拥有多个处理器可以提高插入的并发性,从而可以更大幅度地提高吞吐量。例如,将 700MB 的文件被分解为 10 个不同的 70MB 文档时,如果您使用具有 1.35GHz 处理器的数据库,每个 70MB 文档的插入时间可能小于一分钟。如果这些 CPU 都可用,这 10 个文档可以并发插入到数据库中。采用此策略,插入整个 700MB 文档总耗时约一分钟。

不幸的是,计算这些比较不是一门真正的科学。每个数据库的性能可能都不同,这取决于若干因素,包括操作系统、可用的处理能力、内存和模式定义。在您的环境中进行性能优化的最佳方法是实施这些策略并确定它们各自的优势。

Oracle XML DB 与商用现成 (COTS) ETL 产品的比较

一些商用的提取、转换和加载 (ETL) 工具可用于将文件中的数据加载到数据库中。这些工具的特色是通常有一个具有拖放功能的简单前端,可以隐藏实际过程的复杂性。当您在商用 ETL 工具中创建 XML 加载进程时,需要定义要提取的域。如果未指定特定的 XPath,将无法从文档中收集数据。In the case of complex XML documents, the advantage of Oracle XML DB is that it takes a database-centric view of documents and shreds each document into an object-relational model.将文件成功插入数据库后,该文件中包含的所有数据都可供访问,而无需重新进行分析。

Oracle XML DB 最大的优势之一在于它是 Oracle 数据库的一个标准特性,无需额外的许可。但如果某个组织并不在意许可费用,它为什么要使用 Oracle XML DB 进行 XML 内容管理,而不采用以 ETL 为重点的公司的工具呢?要了解答案,有必要了解 Oracle XML DB 技术是如何满足管理非常复杂的 XML 的独特要求的。

复杂 XML 内容所带来的挑战

当 XML 的内容灵活、经常变化、递归并且非常庞大时,开发人员无疑将遇到简单格式情况下不存在的某些挑战。复杂 XML 文档的一种可能情况是,它的 XML 模式可能非常庞大,并且在保持有效的同时允许极大的灵活性。使用灵活的 XML 模式是一种常见策略,旨在满足公司具体要求的同时支持整个业界的标准。

例如,考虑一个被三家公司作为标准采用的 XML 模式。除了共享元素或标准元素之外,此 XML 模式还需要包括各家公司的所有特定于公司的定义。为满足这一要求,此 XML 模式的设计借助通用容器元素获得了极大的灵活性,这些通用容器元素引用所有可能的公司特定元素,并且允许大多数的元素引用发生零次或多次。因此,元素完全不同的文档对于相同的 XML 模式都有效。从开发的角度来看,这种灵活性使得编写用于提取所需数据的 XML 分析器变得困难,这是因为元素的出现难以预测。由于 COTS ETL 工具和自定义分析器需要特定的 XPath 来提取数据,因此需要检查每个可能的 XPath 以确保捕获文档中所有的数据。这是一个不切实际的解决方案,因为可能 XPath 的数目惊人。而且,如果模式中存在递归或循环引用,XPath 的数目将是个无限值。如果检测到未捕获的数据,唯一的解决方案是重新分析整个文件,这是一个代价高昂的操作,应尽可能避免。

考虑下面的 XML 模式(注意因通用元素所产生的循环引用和灵活性):

startData.xsd
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:bc="startData.xsd" xmlns:xn="standardData.xsd" xmlns:es="CompanySpecific.1.0.xsd" <br/>
xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb" targetNamespace="startData.xsd" 
  elementFormDefault="qualified" attributeFormDefault="unqualified">
<import namespace="standardData.xsd" schemaLocation="standardData.xsd"/>
<import namespace="CompanySpecific.1.0.xsd" schemaLocation="CompanySpecific.1.0.xsd"/>
<element name="rootElement" xdb:defaultTable="XML_DEFAULT">
<complexType>
<sequence>
        <element name="fileHeader">
                <complexType>
                        <attribute name="fileFormat" type="string" use="required"/>               
                        <attribute name="companyName" type="string" use="optional"/>
                </complexType>
        </element>
        <element name="fileData" maxOccurs="unbounded">
                <complexType>
                        <choice>
                                <element ref="xn:childContainer" maxOccurs="unbounded"/>
<element ref="xn:salesInformation" maxOccurs="unbounded"/>
                        </choice>
                </complexType>
        </element>
        <element name="fileFooter">
                <complexType>
                        <attribute name="timeStamp" type="string" use="required"/>
                </complexType>
        </element>
</sequence>
</complexType>
</element>
</schema>
standardData.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:xn="standardData.xsd" targetNamespace="standardData.xsd" 
  elementFormDefault="qualified" attributeFormDefault="unqualified" xmlns:cs="CompanySpecific.1.0.xsd" >
<import namespace="CompanySpecific.1.0.xsd" schemaLocation="CompanySpecific.1.0.xsd"/>
<element name="childContainer">   
<complexType>
        <sequence>
                <element name="attributes" minOccurs="0">
                <complexType>
                <all>
                        <element name="childLabel" minOccurs="0"/>
                        <element name="childType" minOccurs="0"/>
                </all>
                </complexType>
                </element>
                <choice minOccurs="0" maxOccurs="unbounded">
                        <element ref="xn:childContainer"/>
                        <element ref="xn:CompanySpecificContainer"/>
                        <element ref="xn:salesInformation"/>
                </choice>
        </sequence>
</complexType>
</element>
<element name="salesInformation"> 
<complexType>
        <sequence>
                <element name="storeNumber" type="string" minOccurs="0"/>
                <element name="orderNumber" type="string" minOccurs="0"/>
                <element name="salesDate" type="string" minOccurs="0"/>
<element name="product" type="string" minOccurs="0"/>
<element name="quantity" type="string" minOccurs="0"/>
<element name="price" type="string" minOccurs="0"/>
<choice minOccurs="0" maxOccurs="unbounded">
                        <element ref="xn:childContainer"/>
                </choice>
        </sequence>
</complexType>
</element>
<element name="CompanySpecificContainer">
<complexType>
        <sequence>
                <element name="attributes" minOccurs="0">
                <complexType>
                <all>
                        <element name="csDataType" minOccurs="0"/>
                        <element name="csDataFormat" minOccurs="0"/>
                        <element ref="cs:csStore" minOccurs="0"/>
<element ref="cs:csProduct" minOccurs="0"/>
                </all>
                </complexType>
                </element>
                <choice minOccurs="0" maxOccurs="unbounded">
                        <element ref="xn:CompanySpecificContainer"/>
                </choice>
        </sequence>
</complexType>
</element>
</schema>
CompanySpecific.1.0.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:cs="CompanySpecific.1.0.xsd" 
  targetNamespace="CompanySpecific.1.0.xsd" elementFormDefault="qualified" attributeFormDefault="unqualified">
<element name="csStore">
    <complexType>
      <sequence>
        <element name="label" type="string" minOccurs="0"/>
        <element name="name" type="string" minOccurs="0"/>
        <element name="value" type="string" minOccurs="0"/>
      </sequence>
    </complexType>
  </element>
<element name="csProduct">
    <complexType>
      <sequence>
        <element name="label" type="string" minOccurs="0"/>
        <element name="name" type="string" minOccurs="0"/>
        <element name="value" type="string" minOccurs="0"/>
      </sequence>
    </complexType>
  </element>
</schema>

该 XML 模式可用作传输销售和库存数据的行业标准。注意,在 standardData.xsd 命名空间中,childContainer 元素和 companySpecificContainer 元素是可选的自引用。在这个特定的定义中,该设计使各个公司能够使用父/子关系决定数据的粒度。该模式还允许每个公司选择库存数据和/或销售数据。它还进一步允许每个公司包括零个或多个店铺、产品和销售,这一切都取决于各自的需求但要符合相同的灵活格式。

例如,如果一家假想的公司 ABC 希望包括多家店面的库存和销售数据,它可以使用 CompanySpecificContainer 元素集合来标识各家店面(父),使用 CompanySpecificContainer 元素集合来标识各家店面的产品(子)。ABC 的一个有效文档可以是

CompanyABC.xml
<?xml version="1.0"?>
<rootElement xmlns="startData.xsd" xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<fileHeader fileFormat="v1.0" companyName="CompanyABC"/>
<fileData>
<xn:childContainer>
        <xn:attributes>
                <xn:childLabel>Store 0001 Inventory</xn:childLabel>
<xn:childType>Stock</xn:childType>
</xn:attributes>
        <xn:CompanySpecificContainer>
                <xn:attributes>
<xn:csDataType>csStore</xn:csDataType>                                      
<xn:csDataFormat>CompanySpecific.1.0</xn:csDataFormat>
<cs:csStore>
                        <cs:label>Store 0001</cs:label>
                        <cs:name>Product 1</cs:name>
                        <cs:value>In Stock</cs:value>
</cs:csStore>
</xn:attributes>
        <xn:CompanySpecificContainer>     
                        <xn:attributes>
<xn:csDataType>csProduct</xn:csDataType>                            
<xn:csDataFormat>CompanySpecific.1.0</xn:csDataFormat>
<cs:csProduct>
                                <cs:label>Product 1</cs:label>
                                <cs:name>Quantity</cs:name>
                                <cs:value>10</cs:value>
</cs:csProduct>
</xn:attributes>
                </xn:CompanySpecificContainer>
</xn:CompanySpecificContainer>
<xn:salesInformation>
        <xn:storeNumber>Store 0001</xn:storeNumber>
<xn:orderNumber>12345</xn:orderNumber>
        <xn:salesDate>20-SEP-2007</xn:salesDate>
<xn:product>Product 1</xn:product>
<xn:quantity>1</xn:quantity>
<xn:price>110.00</xn:price>
</xn:salesInformation>
</xn:childContainer>
</fileData>
<fileFooter timeStamp="20-SEP-2007"/>
</rootElement>

然而,如果另一家公司 XYZ 只有一个店面并且选择在文件中只包含标准的销售数据,它可以省略 childContainer 元素,只包括 salesInformation 元素集合。XYZ 公司仅描述标准销售数据的一个有效文档可能如下所示:



CompanyXYZ.xml

<?xml version="1.0"?>
<rootElement xmlns="startData.xsd" xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd" <br />  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<fileHeader fileFormat="v1.0" companyName="CompanyXYZ"/>
<fileData>
<xn:salesInformation>
        <xn:storeNumber>Store 0001</xn:storeNumber>
<xn:orderNumber>12345</xn:orderNumber>
        <xn:salesDate>20-SEP-2007</xn:salesDate>
<xn:product>Product 1</xn:product>
<xn:quantity>1</xn:quantity>
<xn:price>110.00</xn:price>
</xn:salesInformation>
</fileData>
<fileFooter timeStamp="20-SEP-2007"/>
</rootElement>

这些文档差别很大,但在 XML 模式中都有效。该设计通过在 XML 模式中使用一个灵活的格式,简化了整个业界标准在不同公司的使用。而且,对通用容器元素进行递归引用使每个公司可以在遵循 XML 模式的同时确定包括多少详细信息。例如,一个用于从 CompanyABC.xml 中提取现存数量数据的 XPath 如下

'/rootElement/fileData/xn:childContainer/xn:CompanySpecificContainer/
  xn:CompanySpecificContainer/xn:attributes/cs:csProduct/cs:value'

然而,如果该公司希望包括更高粒度的店铺数据,可以针对分店添加另一个子元素,如

'/rootElement/fileData/xn:childContainer/xn:CompanySpecificContainer/xn:CompanySpecificContainer/
  xn:CompanySpecificContainer/xn:attributes/cs:csProduct/cs:value'
此 XML 模式的设计允许文件包含丰富的由各家公司单独确定的内容。通过使用通用容器元素和可选的引用,每个文档都类似于一个它自己的数据库。由于每个文件的不可预见性,使用自定义代码或 COTS ETL 工具管理此 XML 将会是一件繁重的开发任务,可能需要持续的维护和支持。如果任何一个使用此 XML 模式的公司包括了一个新的 XPath,需要修改提取代码以捕获此数据。任何经过分析但不具备更新的 XPath 的文件都需要重新进行彻底的分析。该示例演示了复杂 XML 模式所带来的切实的挑战以及负责管理这类内容的开发人员所面临的困难。

Oracle XML DB 解决方案

这个与 XPath 映射有关的问题(如上例所示)在 Oracle XML DB 中并不存在,这是因为整个文件存储在数据库中。文档一旦被插入,可立即查询文档的内容。不论 XML 模式的灵活性如何,均可使用适当的 XPath 访问文档中包含的数据。这就提供了一个无可匹敌的优势:使可用性达到最大程度并将维护成本降至最低。

要实施 XML DB 解决方案,首先注册 XML 模式(目录 XML_TEST 中的定义文件和文档):

begin
DBMS_XMLSCHEMA.REGISTERSCHEMA(
        schemaurl => 'CompanySpecific.1.0.xsd',
        schemadoc => BFILENAME ('XML_TEST','CompanySpecific.1.0.xsd')
        );
DBMS_XMLSCHEMA.REGISTERSCHEMA(
        schemaurl => 'standardData.xsd',
        schemadoc => BFILENAME ('XML_TEST','standardData.xsd')
        );
DBMS_XMLSCHEMA.REGISTERSCHEMA(
        schemaurl => 'startData.xsd',
        schemadoc => BFILENAME ('XML_TEST','startData.xsd')
        );                              
end;    
/
既然您已经为我们的 XML 模式创建了对象关系结构,您可以将 XML 文件插入到默认表(在根元素的注释中指定)中。
insert into XML_DEFAULT values (XMLTYPE(BFILENAME ('XML_TEST','CompanyABC.xml'),nls_charset_id('AL32UTF8')));
/
文件在不到一秒的时间内成功插入。可立即对这些数据进行关系访问。下面的查询访问示例描述了当前库存:

SELECT extractValue(object_value,'/rootElement/fileFooter/@timeStamp')  start_date, 
extractValue(object_value,'/rootElement/fileHeader/@companyName') companyName, 
extractValue(object_value,'/rootElement/fileHeader/@fileFormat') fileFormat,
extractValue(value(b),'/xn:childContainer/xn:attributes/xn:childLabel', 
   'xmlns:xn="standardData.xsd"') childLabel,
extractValue(value(b),'/xn:childContainer/xn:attributes/xn:childType', 
   'xmlns:xn="standardData.xsd"') childType,
extractValue(value(c),'/xn:CompanySpecificContainer/xn:attributes/xn:csDataType', 'xmlns:xn="standardData.xsd"') csDataType,
extractValue(value(c),'/xn:CompanySpecificContainer/xn:attributes/xn:csDataFormat', 
   'xmlns:xn="standardData.xsd"') csDataFormat,
extractValue(value(c),'/xn:CompanySpecificContainer/xn:attributes/cs:csStore/cs:label', 
   'xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd"') csStoreLabel,
extractValue(value(c),'/xn:CompanySpecificContainer/xn:attributes/cs:csStore/cs:name', 
   'xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd"') csStoreName,
extractValue(value(c),'/xn:CompanySpecificContainer/xn:attributes/cs:csStore/cs:value', 
   'xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd"') csStoreValue,
extractValue(value(c),'/xn:CompanySpecificContainer/xn:CompanySpecificContainer/xn:attributes/xn:csDataType', 
   'xmlns:xn="standardData.xsd"') csDataTypeL2,
extractValue(value(d),'/xn:CompanySpecificContainer/xn:attributes/xn:csDataFormat', 
   'xmlns:xn="standardData.xsd"') csDataFormatL2,
extractValue(value(d),'/xn:CompanySpecificContainer/xn:attributes/cs:csProduct/cs:label', 
   'xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd"') csProductLabel,
extractValue(value(d),'/xn:CompanySpecificContainer/xn:attributes/cs:csProduct/cs:name', 
   'xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd"') csProductName,
extractValue(value(d),'/xn:CompanySpecificContainer/xn:attributes/cs:csProduct/cs:value', 
   'xmlns:xn="standardData.xsd" xmlns:cs="CompanySpecific.1.0.xsd"') csProductValue
from 
XML_DEFAULT a
,TABLE(XMLSequence(Extract(object_value, '/rootElement/fileData/xn:childContainer', 
   'xmlns:xn="standardData.xsd" xmlns="startData.xsd"'))) b
,TABLE(XMLSequence(Extract(value(b), '/xn:childContainer/xn:CompanySpecificContainer', 
   'xmlns:xn="standardData.xsd"'))) c
,TABLE(XMLSequence(Extract(value(c), '/xn:CompanySpecificContainer/xn:CompanySpecificContainer', 
   'xmlns:xn="standardData.xsd"'))) d
/

...
                              
snipped
...
该解决方案允许管理任何符合 XML 模式定义的文档。通过 Oracle XML DB 以数据库为中心的 XML 文档视图,XML 文档可以具有丰富的内容,同时提供了一个可避免开发复杂性的抽象层,这种复杂性是其他任何 ETL 技术无法避免的。

该示例演示了 Oracle XML DB 无可匹敌的 XML 存储和检索能力,但复杂 XML 模式的另一特色在于经常会更改 XML 模式定义。Oracle XML DB 如何简化对 XML 模式的更改呢?

管理 XML 模式更改

在前面的示例中,通过使用通用容器元素和对公司特定元素的可选引用提供了模式灵活性。尽管这一设计在 XML 模式中提供了极大的灵活性,但如果各个公司选择在其文件中包含额外的数据,CompanySpecific.1.0.xsd 命名空间可能需要进行更改。

模式定义的更改对基于 XML 的解决方案而言始终是个问题。这是预料之中的,因为 XML 模式应当用于验证 XML 文档。如果文档包含有模式中未定义的元素,则文档是无效的。过去,这一直是 Oracle XML DB 的一个弱点,因为对已注册的 XML 模式进行更改需要一个使用 copyEvolve 过程的复杂的、代价高昂的操作。该过程锁定资源,创建临时表,将该模式的 XML 表中的所有数据移至临时表中,应用模式更改,然后将数据移回 XML 表。XML 表中的数据越多,该操作耗时就越长、代价就越高。根据表大小,完成模式演变以添加单个元素或属性可能需要数小时。对复杂的 XML 而言,该过程不是一个用于管理模式变化的适当解决方案。

为了应对这一局限性,Oracle 在 Oracle XML DB 11g 中引入了一个名为 inPlaceEvolve 的新过程,它使相同的模式更改成为一个无需进行数据移动的联机操作。相反,该过程在修改模式注册期间创建的数据库对象的同时,原样保留相关的数据。该增强功能在解决复杂 XML 模式常见的定义更改问题上起到至关重要的作用。

使用我们前面的示例,考虑在 csProduct 定义中添加其他元素的情况:

CompanySpecific.1.1.xsd
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:cs="CompanySpecific.1.0.xsd" 
 targetNamespace="CompanySpecific.1.0.xsd" elementFormDefault="qualified" <br /> attributeFormDefault="unqualified">
<element name="csStore">
    <complexType>
      <sequence>
        <element name="label" type="string" minOccurs="0"/>
        <element name="name" type="string" minOccurs="0"/>
        <element name="value" type="string" minOccurs="0"/>
      </sequence>
    </complexType>
  </element>
<element name="csProduct">
    <complexType>
      <sequence>
        <element name="label" type="string" minOccurs="0"/>
        <element name="name" type="string" minOccurs="0"/>
        <element name="value" type="string" minOccurs="0"/>
        <element name="class" type="string" minOccurs="0"/>
      </sequence>
    </complexType>
  </element>
</schema>

利用 Oracle XML DB 11g,这一修改可以迅速完成,要求的资源也最少。该新过程需要模式 URL 和一个符合 xdiff XML 模式的 XMLType 文档 (XMLDiff)。XMLDiff 文档是一个经过特殊格式化的文档,可以反映 XML 模式的变化。您不必手动创建 XMLDiff 文档,Oracle 数据库中的 xmldiff 函数会自动创建。

首先,使用更新后的 XML 模式定义 CompanySpecific.1.1.xsd 创建一个新的模式文件。然后,使用 Oracle 数据库的 xmldiff 函数(旧模式 作为第一个参数,新模式作为第二个参数:

var oldSchemaDoc clob;
var newSchemaDoc clob;
 begin
     :oldSchemaDoc := xmltype( bfilename ( 'XML_TEST', 'CompanySpecific.1.0.xsd') ,
                              


        nls_charset_id('AL32UTF8') ).getClobVal();
      :newSchemaDoc := xmltype( bfilename ( 'XML_TEST', 'CompanySpecific.1.1.xsd') ,
                              


        nls_charset_id('AL32UTF8') ).getClobVal();
    end;
/
                            
您可以使用以下语句查看 XMLDiff 文档:
select xmldiff(xmltype(:oldSchemaDoc),xmltype(:newSchemaDoc)).getClobVal() from dual;
/
为简便起见,使用 CLOB 变量存储 XMLDiff 文档。
var diffXMLDoc clob;
begin
      select xmldiff(xmltype(:oldSchemaDoc),xmltype(:newSchemaDoc)).getClobVal() into :diffXMLDoc from dual;
end;
/ 
现在 XMLDiff 文档可用,您可以调用 inPlaceEvolve 过程联机修改 XML 模式。
SQL> alter session set events = '31150 trace name context forever, level 0x200000';

Session altered.

SQL> 
SQL> BEGIN
  2  DBMS_XMLSCHEMA.inPlaceEvolve('CompanySpecific.1.0.xsd',  xmltype(:diffXMLDoc) );
  3  END;
  4  /

PL/SQL procedure successfully completed.
经过对跟踪文件的检查发现,表示修改后的复杂元素的数据库类型已更改为包括新元素:
change to ct  sqltype = csProduct1046_T
 ------------ QMTS Executing SQL ------------ 
ALTER TYPE "XMLTEST"."csProduct1046_T" ADD ATTRIBUTE "class" VARCHAR2(4000 CHAR) CASCADE NOT INCLUDING TABLE DATA 
/
 --------------------------------------------
该新特性的引入使得高效地管理 XML 模式的变化成为可能,在模式演变期间,即使有大量文档,速度也会很快。这是一个主要增强,它提高了将 Oracle XML DB 用作大型企业解决方案的可行性。

实际应用

Oracle XML DB 11g 提供了一个全面、高效的内容管理解决方案,它远比任何同类方案更有用、更实用。通过采用每个文档的以数据库为中心的视图,Oracle XML DB 提供了一个用于存储和检索 XML 内容的创新、强大的方法。通过多种存储选项,可以高效地管理所有文档,而不论其大小和复杂性。高效修改 XML 模式定义的新特性使 Oracle XML DB 成为频繁变化的内容的理想解决方案。这些特性能够应对管理复杂 XML 内容所带来的挑战,并且提供了一个值得所有组织认真考虑的解决方案。

尽管本文描述的复杂 XML 的使用可能看上去过于复杂,但它仍然作为多个行业的标准逐渐兴起。例如,在电信行业,无线通信公司已经使用与文中所示类似的 XML 模式来分配传输量度(参见 3GPP)。考虑到复杂 XML 所提供的重要价值和灵活性以及 Oracle XML DB 所具备的前所未有的高效管理该内容的能力,随着更多的决策者意识到 Oracle XML DB 11g 的全部潜力,XML 的这种应用可能会变得更为普遍。


V.J. JainVarun Jain Inc 公司 Oracle 应用产品和 Oracle 数据库首席顾问。他的其他文章见 Oracle-Developer.com

将您的意见发送给我们