WEB开发网
开发学院数据库DB2 DB2 最佳实践: 使用 DB2 pureXML 管理 XML 数据的... 阅读

DB2 最佳实践: 使用 DB2 pureXML 管理 XML 数据的最佳实践,第 4 部分:XML 索引使用指南和 XML 名称空间处理

 2009-11-12 00:00:00 来源:WEB开发网   
核心提示:XML 索引的使用指南在下面章节中描述了在 XML 数据上创建索引的指南,以及如何有效的使用索引,DB2 最佳实践: 使用 DB2 pureXML 管理 XML 数据的最佳实践,第 4 部分:XML 索引使用指南和 XML 名称空间处理,定义索引对于最大化你的 XQuery 和 SQL/XML 语句的性能非常关键, D

XML 索引的使用指南

在下面章节中描述了在 XML 数据上创建索引的指南,以及如何有效的使用索引。

定义索引

对于最大化你的 XQuery 和 SQL/XML 语句的性能非常关键。 DB2 允许你在 XML 列上定义path-specificXML 索引。这意味着你可以把选中的在谓词和连接中经常用到的元素和属性编入索引中。例如,对于有 principal amounts 的交易下面的索引可以帮助你加速搜索:


清单 44. 在 principal amounts 上的 XML 索引

  create index tdpa on trades(tradedoc) generate keys 
 using xmlpattern 
   '/FpML/trade/termDeposit/principal/amount' as sql double;

这个语句会创建一个现在存 TRADES 表的 TRADEDOC 列中的 XML 文档的索引。将为每个匹配指定的 XPath 标的式的节点创建一个索引键。索引键在文档插入、更新或删除时被添加和删除。<TIP>记住 XML 索引只能被定义在一个单独的 XML 列上,不能有组合键,不过可以为每个基础表生成多个键值。例如,一个定义在‘ /FpML/trade/fxSingleLeg/*/paymentAmount/amount ’上的索引将为每个外汇交易衍生工具创建两个键值,因为这样的文档都包含两个 amount 元素。记住 XML 索引不包含文档输入的也不包含索引路径。因此,对于描述了bulletPayment 或外汇交易事务的交易文档在清单 44 中的索引将不包含任何键,因为它们不包括 /FpML/trade/termDeposit/principal/amount 路径。

与关系型索引一样 XML 索引会消耗表空间的空间,并在文件被插入、更新或删除后必须进行维护(保持实时)。因此,你需要在它们对查询的好处和存储维护它们需要额外的资源需求之间找到平衡。一个 XML 索引的大小和维护开销是和每个匹配索引 XMLPATTERN 的文档中元素和属性数目直接相关的。下一章节解释了如何尽可能保持较小 XML 索引开销。

你可以在定义 XML 索引【 3 】中找到更多的细节。我们认为 你记得基本的指定索引路径使用元素和属性节点名、“ / ”,“ // ”和“ * ”符号以及每个索引以及每个索引包含一种 SQL 类型的必要性。在下面的章节中,我们将侧重于索引定义的最佳实践。

只要有可能就使用完全指定的路径来定义索引

假设你需要确保在外汇兑换交易 payment amount 要求的中良好的查询性能。因为每个外汇兑换交易都有两个路径对应一个 payment amount 即

/FpML/trade/fxSingleLeg/exchangedCurrency1/paymentAmount/amount and

/FpML/trade/fxSingleLeg/exchangedCurrency2/paymentAmount/amount,

/FpML/trade/fxSingleLeg/exchangedCurrency1/paymentAmount/amount 和

/FpML/trade/fxSingleLeg/exchangedCurrency2/paymentAmount/amount,

你打算保持简洁并如图 45 所示定义了一个以“ paymentAmount/amount ”为结尾的的索引。


清单 45. 一个有通配符的索引

create index tpa on trades(tradedoc) generate keys using xmlpattern 
  '//paymentAmount/amount' as sql double;

出于下列原因,这个索引可以被清单 46 中的查询使用:

索引路径比在查询中指定的更简单。

在谓词(数字)中的文本值的数据类型匹配索引类型。


清单 46. 一个涉及 /paymentAmount/amount 查询

select tradeid from trades t where 
 xmlexists('$TRADEDOC/FpML/trade/fxSingleLeg/*/paymentAmount[amount > 
                   1000000 and currency = "USD"]');

然而,索引定义中的 // 对查询具有在前文中讨论过的相同的缺点。首先,在一个确定的元素比起完全指定了路径和指向的情况下,// 意味著 DB2 需要做更多的工作来为索引查找匹配的元素。其次,// 在索引模式中可能会选择比你期望的数目更多的节点。这意味着比起索引会变得比实际需要的大小要更大。如果你更详细的指定路径就可以避免这种情况。


清单 47. 更详细的索引

 create index tfxpa on trades(tradedoc) generate keys using xmlpattern 
 '/FpML/trade/fxSingleLeg/*/paymentAmount/amount' as sql double;

正确的使用 XML 索引数据类型

DB2 支持 5 种不同数据类型的 XML 索引:DOUBLE、VARCHAR(n)、VARCHAR HASHED、DATE 和时间戳。索引数据类型的选择很重要,因为它影响索引在谓词赋值中的使用。例如清单 48 中的索引不能在清单 49 中的查询中使用。


清单 48. 一个使用数字类型的索引

create index thtd on trades(tradedoc) generate keys using xmlpattern 
  '/FpML/trade/tradeHeader/tradeDate' as sql double;



清单 49. 使用字符串谓词的查询

select * 
 from trades 
 where xmlexists('$TRADEDOC/FpML/party[partyId="510026"]')

为什么呢?数字是 510026 在查询谓词中是包含在双引号中的,因此它被解释为一个字符串。因为索引数据类型是 DOUBLE,索引不能被用来决定字符串谓词。你需要定义一个使用 VARCHAR 数据类型的索引(如果你想比较字符串)或者保持 DOUBLE 索引类型并删除数字(数字比较)的双引号

同样的清单 50 中的索引不能被图 51 中的查询使用。这是因为“ 2002-02-14Z ”是一个字符串文字,它匹配 VARCHAR 索引却不匹配 DATE 索引。


清单 50. 一个使用 DATE 类型的索引

create index thtd on trades(tradedoc) generate keys using xmlpattern 
  '/FpML/trade/tradeHeader/tradeDate' as sql date;

xquery for $i in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML 
 where $i/trade[tradeHeader/tradeDate >= "2002-02-14Z"] 
 return $i;

图 51:一个使用 VARCHAR 谓词的查询。

简单的解决方案是把查询中的文字映射为 XML 类型 xs:date,如清单 52 所示。这就可以使用 DATE 索引了。


清单 52. 利用 xs:date 来使用一个 DATE 索引

xquery for $i in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML 
 where $i/trade[tradeHeader/tradeDate >= xs:date("2002-02-14Z")] 
 return $i;

索引数据类型:VARCHAR(n) 和 VARCHAR HASHED

VARCHAR(n) 索引对在被索引的字符串有最大长度“ n ”的情况非常适合,并且索引的元素可以在范围谓词(<,>)中使用。如果你尝试在有长度大于“ n ”的节点上创建一个 VARCHAR(n) 索引,创建将会失败。同样的对一个文档一个插入或更新也会失败,在定义了 VARCHAR(n) 索引的情况下。因此,一个 VARCHAR(n) 索引对索引节点执行了一个长度为“ n ”限制。

另一方面一个 VARCHAR HASHED 索引允许你的索引字符串为任意长度。它们只存储字符串的哈希值而不存储索引的键值。这列索引可以快速评估等价谓词,不过却不能被用作范围谓词或排序。表 53 总结了这个两种索引对 XML 字符数据的属性。

索引类型 用途 是否限制索引键长度?
VARCHAR(N)
所有谓词类型,排序N 字节:最大 N 值取决于索引页大小
VARCHAR HASHED- - 仅限与等价谓词
-- 对长型数据建立索引
 

图 53:VARCHAR(n) 和 VARCHAR HASHED 索引的特征

<TIP>简而言之,对于只会被用于等价谓词的查询的元素或属性,一个 VARCHAR HASHED 索引常常是很好的选择。尤其对于长型数据,一个 VARCHAR HASHED 索引比一个 VARCHAR(n) 索引更小。如果索引是常常被用于评估范围谓词那么就需要使用 VARCHAR(n) 索引。

索引定义中的 text()

在考虑它在索引中的影响之前,让我们简单回顾一下路径表达式中 /text() 的含义。下面是一个定期存款交易文档的一部


清单 54. 定期存款文档的很小一部分

<principal> 
      <currency>EUR</currency> 
      <amount>25000000.00</amount> 
     </principal>

元素节点 <principal>、<currency> 和 <amount>(以及他们各自的关闭标签)提供了文档结构。具体值存放在文本节点 EUR 和 25000000.00 中,它们是树型结构的叶子节点。此外,每个元素节点在子树下面的元素节点都有一个定义为所有文本节点的串联。例如,<principal> 的值是 EUR25000000.00 。更详细的,<currency> 的值是“ EUR ”。

更普遍的情况是叶子元素的值和它们文本节点一样。因为 XML 谓词总是定义在叶子节点,在谓词使用 /text() 通常不会影响查询结果;例如,在清单 55 中的两个查询子句对数据执行了完全一样的过滤器。然而,在返回子句中 /text() 会有所不同。第一个查询返回“ <currency>EUR</currency> ”而第二个查询只返回“ EUR ”。


清单 55. 一个有 /text() 的查询和一个没有 /text() 的查询

xquery for $i in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML/trade 
 where $i/termDeposit/principal/currency = "EUR" 
 return $i/termDeposit/principal/currency; 
 
 xquery for $i in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML/trade 
 where $i/termDeposit/principal/currency/text()= "EUR" 
 return $i/termDeposit/principal/currency/text();

<TIP>一个有 /text() 的谓词只有这个索引也用 /text() 定义时,才可以使用这个索引。这是为了确保在极少的情况或是非叶子元素定义的索引时的正确并一致的行为。例如,<principal> 的值是“ EUR25000000.00 ”,而 <principal>/text() 的值是空。

在清单 55 中的第一查询可以使用图 56 中的第一个索引却不能使用第二个索引。在图 55 中的第二个查询可以使用第二个索引而不是清单 56 中的第一个索引。通常的建议是不要使用 /text(),无论是谓词还是索引定义中。


清单 56. 定义了 /text() 的索引和没有定义 /text() 的索引

create index tradeIdIdx1 on trades(tradedoc) generate keys using xmlpattern 
 '/FpML/trade/termDeposit/principal/currency' as sql varchar hashed; 
 
 create index tradeIdIdx2 on trades(tradedoc) generate keys using xmlpattern 
 '/FpML/trade/termDeposit/principal/currency/text()' as sql varchar hashed;

在非叶子节点上的 XML 索引

让我们在看一下清单 54 的文档小片段并记住 <principal> 的值是 EUR25000000.00 。你可以使用这个操作来编写查询连续的文本节点。


清单 57. 在一个非叶子节点上的谓词

xquery for $doc in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML/trade 
 where $doc/termDeposit/principal = "EUR25000000.00" 
 return $doc/termDeposit/maturityDate;

可以通过在索引路径表述中指定非叶子节点对这些“连续”节点定义索引:


清单 58. 在非叶子节点上的索引

create index tdp on trades(tradedoc) generate keys using xmlpattern 
  '/FpML/trade/termDeposit/principal' as sql varchar(30);

这个索引不像一个关系意义上的复合索引,因为她的数据仍然来自于一个 XML 列。然而,如果你确认索引节点在 <currency> 之间 <amount> 不包含其它子节点的话还是有用的,因为这将在索引键值中包括不希望的数据。

<TIP>在一些意外情况下,很少对非叶子节点建立索引。你应该只在有明显的好处的情况下才对非叶子节点建立索引,除非你对查询谓词和文档结构非常了解。

当我们考虑非叶子节点的时候,我们应该注意另外一个在用通配符定义索引时可能出现的陷阱。假设在 /FpML/trade/termDeposit/* 上定义一个索引,这个索引对“ termDeposit ”元素的所有子元素都有一个条目。如果任何这些子元素是一个非叶子节点,那么相应的键值就可能是多个节点的串联。这也可能意外的超过 VARCHAR(n) 索引的限制。

在 XML 查询中使用索引

在你定义 XML 索引时要谨慎,不过你可能会发现你的索引并是像你期望那样被使用。或许某个查询的性能是令人失望,然后你检查它的查询计划,却发现它执行了一个表扫描而不是一个索引扫描。我们将会列举一些简单例子来展示如何确认索引使用的正确性。

使用通配符查询

匹配索引的两个条件之一是定义索引的路径表达式至少和在索引谓词中的路径表达式大体一样。换句话说,如果索引确定并且查询谓词等于这个索引包含的节点的子集(或全部,不能超过),那么一个索引就能被一个查询使用。


图 1. 索引使用的容量要求
DB2 最佳实践: 使用 DB2 pureXML 管理 XML 数据的最佳实践,第 4 部分:XML 索引使用指南和 XML 名称空间处理

<TIP>对于查询在它们的谓词中使用通配符的情况下可能出现一个问题,它们可能等于超过候选索引所包括的节点。在这种情况下容量需求没有得到满足,索引将不会被使用。例如,在清单 60 中的查询计算了所有涉及一个特定货币类型(EUR)交易的数目。


清单 60. 查询谓词中的通配符

 select count(*) from trades t where xmlexists('$TRADEDOC[FpML//currency="EUR"]');

在路径/FpML/trade/fxSingleLeg//currenc上的一个索引定义不能被用来评估清单 60 中的查询。这个索引将提供一个仅对自己,而没有满足所有查询条件中需要的元素,因此会被使用。

这种情况明显是因为我们的样本数据非常有限,在你没有完全熟悉你的 XML 文档结构的情况下,这很容易被不是用一个索引搞糊。你可能没有注意到一个使用了一个(或多个!)通配符的谓词匹配了的比你想象中要多的节点,而且个别情况下,超过了一个你期望使用的索引所包含的节点。

无论在什么时候都最好是在查询中避免通配符,并使用你想得到的元素和属性的完整路径。如果你使用了通配符(比如 //),那么要确保你出于良好定义的原因,而不是想少打字。

在 XML 连接谓词中的索引

在 7.1.2 章中,我们看到了在一个查询谓词定义中的文字值的类型如何定义比较类型,和它使用一个索引的资格。比如,由于没有可以被识别的文字,一个判断不可能用于一个连接谓词。为了在 XML 连接谓词中使用索引,你需要提供这个连接键的类型信息,这可以使用转换函数来实现。

例如,让我们用 partyId 元素来连接 TRADES 和 PARTIES 表并在每个表上创建一个正确的索引:


清单 61. 在可能的连接键上的索引

create index tptyid on trades(tradedoc) generate keys using 
 xmlpattern '/FpML/party/partyId' as sql double; 
 
 create index pptyid on parties(partyinfo) generate keys using 
 xmlpattern '/Party/PtyID' as sql double;

然后我们执行一个连接来获得一个有各方名字和交易时间的列表:


清单 62. 对交易和交易各方的连接

XQUERY 
 for $pdoc in db2-fn:xmlcolumn("PARTIES.PARTYINFO")/Party 
  for $tdoc in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML 
 where $tdoc/party/partyId=$pdoc/PtyID 
 return <result>{$tdoc/trade/tradeHeader/tradeDate}{$pdoc/Name}</result>;

这个查询不使用清单 61 中定义的任何索引。问题是连接查询没有包含关于 partyId 和 PtyID 可能数据类型的信息。我们可以知道 PartyId 的值是数字值,而 DB2 不是,所以它必须寻找所有类型的匹配值。这个索引定义限制键值如果是数字(SQL DOUBLE)并因此不包含其它类型的键值,比如字母字符串。结果就是 DB2 不能依赖这些索引来进行连接,因为它们可能只包含匹配值的一个子集。

如果你的兴趣仅仅在匹配有数字值得 Party IDs,那么可以使用索引。方法就是使用在连接键值上使用转换函数。在这种情况下,你可以使用构造器 xs:double() 来指出它们是数字。协和在清单 63 中的 XQuery 和 SQL/XML 注释中都有说明。


清单 63. 在连接键值上使用转换函数进行连接

XQUERY 
 for $pdoc in db2-fn:xmlcolumn("PARTIES.PARTYINFO")/Party 
 for $tdoc in db2-fn:xmlcolumn("TRADES.TRADEDOC")/FpML 
 where $tdoc/party/partyId/xs:double(.) = $pdoc/PtyID/xs:double(.) 
 return <result>{$tdoc/trade/tradeHeader/tradeDate}{$pdoc/Name}</result>; 
 
 -- SQL/XML 
 select xmlquery('<result>{$TRADEDOC/FpML/trade/tradeHeader/tradeDate} 
         {$PARTYINFO/Party/Name}</result>') 
 from trades, parties 
 where xmlexists('$TRADEDOC/FpML/party[partyId/xs:double(.) = 
                   $PARTYINFO/Party/PtyID/xs:double(.)]');

注意,这个查询连接顺序的 SQL/XML 版本,把 TRADES 表变成这个连接的内部表,这样我们可以使用在 TRADES 表中的索引 tptyid 。这个查询的 XQuery 版本有可能使用也有可能不是用索引,这取决于查询优化器选择什么连接顺序。

<TIP>总结,要在 XML 连接查询中使用索引,应该随时转换连接谓词为 XML 索引的类型。否则,查询语义不会使用索引。如果 XML 索引被定义为 DOUBLE,就使用 xs:double 转换连接谓词。如果 XML 索引定义为 VARCHAR,就使用 fn:string 来转换连接谓词,等等,如下表所显示的:

Index SQL type Cast join predicate using: Comment
Doublexs:doubleFor any numeric comparison
varchar(n), varchar hashedfn:stringFor any string comparison
Datexs:dateFor date comparison
Timestampxs:dateTimeFor timestamp predicates

图 64:在连接中使用的转换函数类型

处理 XML 名称空间

XML 名称空间是一个 W3C XML 标准在 XML 文档中提供了唯一的名称元素和属性。 XML 文档可能包含来自于其它词汇的元素和属性,却又有相同的名字。通过为每个词汇给定一个名称空间,解决了相同元素和属性之间的容易混淆的问题。 DB2 版本 9.5 中所有 pureXML 功能都支持 XML 名称空间,比如 SQL/XML、XQuery、XML 索引以及 XML 模式操作。我们回顾名称空间声明,然后展示如何在查询和索引定义中使用名称空间。

生命 XML 名称空间

在 XML 文档中,XML 名称空间是由保留属性xmlns声明的,这些值必须包含一个通用资源标识符(URI)。 URIs 被作为标识符;它们通常看起来像一个 URL 不过他们没有存在的网页。一个名称空间声明也可以包含一个前缀,用来定位这个名称空间的元素和属性。

图 65:一个使用名称空间声明来 INSERT 一个 FpML 文档。第一个 xmlns 属性没有定义一个前缀因此并不是一个默认名称空间。

<TIP>在这个没有名称空间前缀的域中的所有元素都不会自动继承默认名称空间和属性。在文档中声明的第 2 个和第 3 个名称空间为前缀“ fpml ”和“ xsi ”分别分配了它们的 URIs 。前缀“ fpml ”没有在这个文档中使用。前缀“ xsi ”被用来显示属于模式名称表空间的属性“ schemaLocation ”和“ type ”,因此有特殊的含义。例如,属性 xsi:schemaLocation 定义了本文遵守的 XML 模式和在那里可以找到这个模式。


清单 65. 把名称空间声明(部分清单)插入文档
insert into trades values (120, 
 '<FpML xmlns="http://www.fpml.org/2007/FpML-4-3" 
 xmlns:fpml="http://www.fpml.org/2007/FpML-4-3" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  version="4-3" 
  xsi:schemaLocation="http://www.fpml.org/2007/FpML-4-3 ../fpml-main-4-3.xsd 
          http://www.w3.org/2000/09/xmldsig# ../xmldsig-core-schema.xsd" 
  xsi:type="DataDocument"> 
  <trade> 
  <tradeHeader> 
   <partyTradeIdentifier> 
   <partyReference href="party1"/> 
   <tradeId tradeIdScheme="http://www.MyGlobalIntl.com/trade-id">MyGlobal123</tradeId> 
    </partyTradeIdentifier> 
    <partyTradeIdentifier> 
     <partyReference href="party2"/> 
     <tradeId tradeIdScheme="http://www.NationalV.com/trade-id">123</tradeId> 
    </partyTradeIdentifier> 
    <tradeDate>2001-04-29Z</tradeDate> 
   </tradeHeader> 
   <bulletPayment> 
… . 
 </FpML>');

查询中的名称空间

我们的查询例子到目前为止都是假设元素和属性名称不是任何名称空间的一部分。很重要的是要认识到如果不改变,这些查询的例子将不会返回任何有名称空间的 XML 文档。

<TIP>这是因为一个没有名称空间的元素是不同于在名称空间中有相同名字的元素。名称空间是一个元素名称的核心部分。让我们来看下面测查询:


清单 66. 如果没有名称空间的查询
select tradeid, t.* 
 from trades, xmltable('$TRADEDOC/FpML' 
 columns 
 tradeDate  date    path  'trade/tradeHeader/tradeDate', 
 partyId1   integer  path  'party[@id="party1"]/partyId' , 
 partyId2   integer  path  'party[@id="party2"]/partyId' 
 ) as t;

这个查询将把除了清单 65 中用 TRADEID 120 最新插入的文档外的所有交易文档返回,因为它的路径表达式和谓词不被元素和属性所属的名称空间允许。确保返回所有和谓词匹配的交易的一个简单的办法是,忽略名称空间在名称空间前缀使用通配符。通配符“ * ”匹配所有名称空间也包括无名称空间。这个查询返回所有交易的行,无论文档有没有名称空间:


清单 67. 查询中使用名称空间的通配符
select tradeid, t.* 
 from trades, xmltable('$TRADEDOC/*:FpML' 
 columns 
 tradeDate  date    path '*:trade/*:tradeHeader/*:tradeDate', 
 partyId1   integer  path '*:party[@id="party1"]/*:partyId' , 
 partyId2   integer  path '*:party[@id="party2"]/*:partyId' 
 ) as t;

<TIP>如果你知道所有你希望查询的元素属于一个特定的名称空间,你就可以用 XMLNAMESPACES() 函数来指定名称空间。对于 XMLTABLE,在 row-generating 和所有 column-generating 表达式中都应用了默认名称空间。


清单 68. 声明一个默认元素名称空间
select tradeid, t.* 
 from trades, xmltable(XMLNAMESPACES 
   (DEFAULT ‘ http://www.fpml.org/2007/FpML-4-3 ’ ),  '$TRADEDOC/FpML' 
 columns 
 tradeDate  date   path  'trade/tradeHeader/tradeDate', 
 partyId1  integer  path  'party[@id="party1"]/partyId' , 
 partyId2  integer  path  'party[@id="party2"]/partyId' 
 ) as t;

注意,在图 68 中的查询只从一个和名称空间定义匹配的交易文档返回值,因为在我们样本数据中的其它文档没有名称空间。

<TIP>当你文档中只出现一个名称空间时,默认名称空间是一个常用的解决方案,如果你想从多个特定的名称空间中选择元素和属性你需要一个不同的方法。在这种情况下,在你的查询中使用名称空间前缀是最佳选择。

注意,其它 SQL/XML 函数同样需要处理名称空间。在图 69 中“ fpml ”前缀在 XMLQUERY 和 XMLEXISTS 函数中都有定义。没有一个可以让你对一个查询甚至整个会话中的所有 SQL/XML 函数定义一个名称空间的结构。


清单 69. 在 XMLQUERY 和 XMLEXISTS 函数中的名称空间声明
select tradeid, xmlquery( 
  'declare namespace fpml="http://www.fpml.org/2007/FpML-4-3"; 
  $TRADEDOC/fpml:FpML/fpml:trade/fpml:tradeHeader/fpml:partyTradeIdentifier') 
 from trades 
 where 
 xmlexists('declare namespace fpml="http://www.fpml.org/2007/FpML-4-3";  
      $TRADEDOC/fpml:FpML/fpml:trade/fpml:tradeHeader[ 
                 fpml:tradeDate=xs:date("2001-04-29Z")]')%

总结,在对用一个或多个名称空间的文档编写查询时要小心。所有 XPath 表达式都需要包括合适的默认名称表空间或名称空间前缀定义否则你的查询将不会返回你期望的结果。

定义中的名称空间

文档中存在的名称空间同样影响他们所在的索引。

<TIP>有名称空间的文档的索引定义在它们的 XML 模式表达式中需要包含相同的名称空间。在第 7.1 章中定义的索引没有一个会包含在清单 65 中添加到 TRADES 表中文档的,因为索引定义了没有名称空间的特定元素。

这里有有两个关于如何重写清单 50 中索引定义的例子,因此会包含新的文档。第一个例子定义了名称空间前缀并在定义路径的元素名称中使用了它。第二个例子简单定义了一个默认元素名称空间,它应用与这个路径中的所有元素。虽然符号不同,不过两个定义是等价的并且你可以使用任何一个,但是不能两个都用。


清单 70. 含有名称空间声明的索引定义
create index thtdns1 on trades(tradedoc) generate keys using xmlpattern 
 'declare namespace fpml="http://www.fpml.org/2007/FpML-4-3"; 
  /fpml:FpML/fpml:trade/fpml:tradeHeader/fpml:tradeDate' as sql date % 
 
 create index thtdns2 on trades(tradedoc) generate keys using xmlpattern 
 'declare default element namespace "http://www.fpml.org/2007/FpML-4-3"; 
 /FpML/trade/tradeHeader/tradeDate' as sql date %

任何一个索引都可以在下面查询中被使用。虽然查询定义了一个明确的名称空间前缀,第二索引(thtdns2)也可以被使用,因为它逻辑上和第一个等价。


清单 71. 一个有名称空间并可以使用任何一个索引的的查询
select count(*) 
 from trades where 
 xmlexists('declare namespace fpml="http://www.fpml.org/2007/FpML-4-3"; 
    $TRADEDOC/fpml:FpML/fpml:trade/fpml:tradeHeader[fpml:tradeDate  
                      =xs:date("2001-04-29Z")]')%

然而,在清单 70 中的两个索引定义都将包括有名称空间定义的交易文档,它们中任何一个都包括所有剩下没有名称空间的交易文档。如果你想在索引中包括这两种文档的话,你可以在名称前缀中使用通配符:


清单 72. 在名称空间前缀中有通配符的索引定义
create index thtdns3 on trades(tradedoc) generate keys using 
 xmlpattern '/*:FpML/*:trade/*:tradeHeader/*:tradeDate' as sql date %

这个索引也有资格在清单 71 中显示的查询中使用,因为它包含不管有没有名称空间的所有交易文档。这把我们带回了在 7.2.1 中讨论过的索引“容量”需求。一个有名称空间通配符的路径表达式可能包含比有一个指定名称空间的相同 XPath 表达式有更多的 XML 元素。因此,用名称表空间匹配索引的规则是对我们已知规则的拓展。

Tags:DB 最佳 实践

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接