SQL2005用XML数据类型进行数据建模(一)

日期: 2008-06-09 作者:Shankar Pal 来源:TechTarget中国

  相同或不同的表


  XML数据类型列可以在包含其他关系列的表中创建,也可以在与主表之间具有外键关系的独立表中创建。


  在满足下列某个条件时,请在同一个表中创建XML数据类型列:



  • 您的应用程序在XML列上执行数据检索,并且不需要XML列上的XML索引。 或者

  • 您需要在XML数据类型列上生成XML索引,并且主表的主键与其聚集键相同。有关详细信息,请参阅将XML数据类型列编入索引一节。

  在满足下列条件时,请在单独的表中创建XML数据类型列:



  • 您需要在XML数据类型列上生成XML索引,但主表的主键与其聚集键不同,或者主表不具有主键,或者主表是一个堆(也就是说,没有聚集键)。如果主表已经存在,则这可能是真的。

  • 您不希望表扫描由于表中存在XML列(无论它是存储在行中还是存储在行外,都会占用空间)而降低速度。

  XML数据的粒度


  XML列中存储的XML数据的粒度对于锁定和更新特性而言至关重要。SQL Server 对XML和非XML数据采用了相同的锁定机制。因此,行级锁定会导致相应行中的所有XML实例被锁定。当粒度比较大时,锁定大型 XML 实例以便进行更新会导致多用户场合下的吞吐量下降。另一方面,严重的分解会丢失对象封装并提高重新组合成本。


  对XML实例进行更新会将现有实例替换为更新后的实例,即使只修改单个属性的值。XML数据粒度越大,更新成本就越高。较小的XML实例会产生较高的更新性能。


  对于良好的设计而言,重要的是保持数据建模需要与锁定和更新特性之间的平衡。


  非类型化、类型化和受约束的XML数据类型


  SQL Server 2005 XML数据类型实现了ISO SQL-2003标准XML数据类型。因此,它可以在非类型化XML列中存储格式规范的XML1.0文档以及带有文本节点和任意数量顶级元素的所谓的XML内容片段。系统将检查数据的格式是否规范,不要求将列绑定到XML架构,并且拒绝在扩展意义上格式不规范的数据。对于非类型化XML变量和参数,也是如此。


  如果您具有描述XML数据的XML架构,则可以将这些架构与XML列相关联,以便产生类型化 ML。XML架构用于对数据进行有效性验证,在查询和数据修改语句编译过程中执行比非类型化XML更准确的类型检查,以及优化存储和查询处理。


  在下列条件下,请使用非类型化XML数据类型:



  • 您没有对应于 XML 数据的架构

  • 您拥有架构,但不希望服务器对数据进行有效性验证。当应用程序在服务器中存储数据之前执行客户端验证时,或者暂时存储根据架构无效的XML数据时,或者使用在服务器中不受支持的架构组件(例如key/keyref)时,有时会出现这种情况。

  在下列条件下,请使用类型化XML数据类型:



  • 您拥有对应于XML数据的架构,并且希望服务器按照XML架构对XML数据进行有效性验证。

  • 您希望充分利用基于类型信息的存储和查询优化。

  • 您希望在查询的编译过程中更充分地利用类型信息。

  类型化XML列、参数和变量可以存储XML文档或内容 – 您在声明时必须将它们指定为标志(分别指定为 DOCUMENT或CONTENT)。而且,您必须提供XML架构集合。如果每个XML实例恰好有一个顶级元素,请指定DOCUMENT;否则,请使用CONTENT。查询编译器在查询编译过程的类型检查中使用DOCUMENT标记来推理唯一的顶级元素。


  除了将XML列类型化以外,您还可以在类型化或非类型化 XML 数据类型列上使用关系(列或行)约束。在下列条件下,请使用约束:



  • 无法在XML架构中表示业务规则。例如,花店的送货地址必须在其营业地点周围50英里范围之内,这可以编写为XML列上的约束。该约束可能涉及到XML数据类型方法。 

  •  您的约束涉及到表中的其他XML列或非XML列。这方面的一个例子是:强制XML实例中存在的Customer ID(/Customer/@CustId) 与关系CustomerID列中的值匹配。

  文档类型定义(DTD)


  XML数据类型列、变量和参数可以使用XML架构而不是DTD加以类型化。然而,对于非类型化和类型化XML,都可以使用内联DTD来提供默认值,以便将实体引用替换为它们的扩展形式。


  您可以使用第三方工具将DTD转化为XML架构文档,并且将XML架构加载到数据库中。


  将XML数据类型列编入索引
 
  可以在XML数据类型列上创建XML索引。这会将该列中XML实例上的所有标记、值和路径编入索引,从而提高查询性能。在下列条件下,您的应用程序可能受益于XML索引:



  • 对XML列进行查询在您的工作负荷中很常见。必须考虑数据修改过程中的XML索引维护成本。 

  •  XML值相对较大,而检索的部分相对较小。生成索引可以避免在运行时分析全部数据,并且因为受益于索引查找而提高查询处理的性能。

  XML列上的第一个索引是”主XML索引”。通过该索引,可以在XML列上创建三种类型的辅助XML索引,从而提高常见种类的查询的速度,如下节所述。


  主XML索引


  这会将XML列中的XML实例内部的所有标记、值和路径编入索引。基表(即包含XML列的表)必须在该表的主键上具有聚集索引;主键用于将索引行与基表中的行相关联。从XML列中检索完整的XML实例(例如select *)。查询使用主XML索引,并返回标量值或使用索引本身的XML子树。


  示例:创建主XML索引


  在我们的多数示例中,都使用带有非类型化XML列的表T (pk INT PRIMARY KEY, xCol XML),这些示例都可以简单地扩展为类型化XML的形式(有关使用类型化XML的信息,请参阅SQL Server 2005联机图书)。为了便于说明,将针对如下所示的XML数据实例描述查询:



<book genre=”security” publicationdate=”2002″ ISBN=”0-7356-1588-2″>
      <title>Writing Secure Code</title>
      <author>
            <first-name>Michael</first-name>
            <last-name>Howard</last-name>
      </author>
      <author>
            <first-name>David</first-name>
            <last-name>LeBlanc</last-name>
      </author>
      <price>39.99</price>
</book>
 
  下面的语句在表T的XML列xCol上创建了名为idx_xCol的XML索引:


  create PRIMARY XML INDEX idx_xCol on T (xCol)


  辅助XML索引


  在创建主XML索引之后,您可能希望创建辅助XML索引来提高工作负荷中的不同种类查询的速度。三种类型的辅助XML索引- PATH、PROPERTY和VALUE分别为基于路径的查询、自定义属性管理场合和基于值的查询提供帮助。PATH索引在列中的所有XML实例上,按照文档顺序生成各个XML节点的(path, value) 对的B+树。PROPERTY索引创建各个XML实例中(PK, path, value)对的聚集B+树,其中PK是基表的主键。最后,VALUE索引在XML列中的所有XML实例中,按照文档顺序创建各个节点的(value, path) 对的 B+ 树。


  以下是创建上述一个或多个索引的一些准则:



  • 如果工作负荷大量使用XML列中的路径表达式,则PATH辅助XML索引可能会加快工作负荷的处理速度。最常见的例子是在T-SQL的where子句中对XML列使用exist()方法。

  • 如果您的工作负荷从单独的使用路径表达式的XML实例中检索多个值,则将各个XML实例中的路径聚集到PROPERTY索引中可能会很有用。这种情况通常出现在属性包场合中,此时对象的属性被获取并且其主键值已知。

  • 如果您的工作负荷涉及到查询XML实例中的值,而不知道包含这些值的元素或属性名称,则您可能需要创建VALUE索引。这通常发生在子代轴查找中,例如 //author[last-name=”Howard”],其中 元素可以出现在层次结构的任意级别上。这种情况还会发生在”通配符”查询中,例如

  /book [@* = “novel”],其中查询将查找具有某个值为 “novel” 的属性的 元素。


  示例:基于路径的查找


  假设下面的查询在您的工作负荷中很常见:


  select pk, xCol
  FROM   T
  where  xCol.exist (’/book[@genre = “novel”]’) = 1
 
  路径表达式 /book/@genre和值”novel”对应于PATH索引的键字段。因此,PATH类型的辅助XML索引对于该工作负荷很有用:



  create XML INDEX idx_xCol_Path on T (xCol)
  USING XML INDEX idx_xCol FOR PATH
 
  示例:获取对象的属性


  请考虑下面的查询,它从表T的各个行中检索一本书的属性”genre”、”title”和ISBN:


  select xCol.value (’(/book/@genre)[1]’, ’varchar(50)’),
   xCol.value (’(/book/title)[1]’, ’varchar(50)’),
   xCol.value (’(/book/@ISBN)[1]’, ’varchar(50)’)
  FROM    T


  在这种情况下,属性索引很有用,其创建方式如下所示:


  create XML INDEX idx_xCol_Property on T (xCol)
  USING XML INDEX idx_xCol FOR PROPERTY
 
  示例:基于值的查询


  在以下查询中,子代轴或自身轴 (//) 指定了部分路径,以便基于ISBN值的查找可以因为使用VALUE索引而受益:


  select xCol
  FROM     T
  where    xCol.exist (’//book[@ISBN = “1-8610-0157-6”]’) = 1
 
  VALUE索引按如下方式创建:


  create XML INDEX idx_xCol_Value on T (xCol)
  USING XML INDEX idx_xCol FOR VALUE


   XML列上的全文索引


  您可以在XML列上创建全文索引,从而将XML值的内容编入索引,而忽略XML标记。属性值没有被编入全文索引(因为它们被视为标记的一部分),并且元素标记被用作标记边界。在某些情况下,可以将全文搜索与XML索引用法结合起来:



  • 首先,使用SQL全文搜索筛选感兴趣的XML值。

  • 接下来,查询这些XML值,这会使用XML列上的XML索引。

  示例:将全文搜索与XML查询结合起来


  在XML列上创建全文索引之后,以下查询将检查XML值是否在书名中包含单词”custom”:


  select *
  FROM   T
  where  CONTAINS(xCol,’custom’)
  AND    xCol.exist(’/book/title/text()[contains(.,”custom”)]’) =1
 
  CONTAINS()方法使用全文索引,将文档中任何地方包含单词”custom”的 XML 值组合为一个子集。exist() 子句确保单词”custom”出现在书名中。


  使用CONTAINS()和XQuery contains()的全文搜索具有不同的语义。后者是子字符串匹配,而前者则是使用单词衍生的标记匹配。因此,如果要搜索标题中的字符串 “run”,则 “run”、”runs”和”running” 都将匹配,因为全文CONTAINS()和Xquery contains() 都满足。然而,上述查询不匹配标题中的单词”customizable”。(全文CONTAINS()失败,而 Xquery contains() 被满足)。通常,对于纯粹的子字符串匹配,应该删除全文CONTAINS() 子句。


  而且,全文搜索采用单词衍生,而XQuery contains() 是一种字面匹配。这一区别将在下一个示例中阐述。


  示例:使用单词衍生对XML值进行全文搜索


  通常情况下,不能排除示例:将全文搜索与XML查询结合起来中的XQuery contains()检查。请考虑查询:


  select *
  FROM   T
  where  CONTAINS(xCol,’run’)
 
  因为使用单词衍生,所以文档中的单词”ran”匹配搜索条件。而且,使用XQuery时不会检查搜索上下文。


  在使用被全文索引的AXSD将XML分解到关系列中时,XML视图上的XPath查询不会对基础表执行全文搜索。


  属性提升


  如果主要是对少量元素和属性值进行查询(例如,基于客户ID查找客户,即指定了/Customer/@CustId的值),您可能希望将这些数量提升到关系列中。当检索了整个XML实例,但只对一小部分XML数据进行查询时,这将很有用。在XML列上创建XML索引是没有必要的;相反,可以将被提升的列编入索引。必须编写查询以使用提升的列(即,查询优化器不会将对XML列的查询重新定向到提升的列)。


  提升的列可以是同一表中的计算列,也可以是表中单独的、用户维护的列。当从各个XML实例中提升唯一值(即单值属性)时,这已足够。然而,对于多值属性,您必须为该属性创建单独的表,如下所述。


  基于XML数据类型的计算列


  可以使用能够激活XML数据类型方法的用户定义函数(UDF)来创建计算列。计算列的类型可以是任何SQL类型,包括XML。以下示例说明了这一点。


  示例:基于XML数据类型方法的计算列


  为书籍的 ISBN 创建用户定义的函数:
  create FUNCTION udf_get_book_ISBN (@xData xml)
  RETURNS varchar(20)
  BEGIN
     DECLARE @ISBN   varchar(20)
     select @ISBN = @xData.value(’/book[1]/@ISBN’, ’varchar(20)’)
     RETURN @ISBN
  END
 
  为 ISBN 向表中添加一个计算列:


  alter TABLE      T
  ADD   ISBN AS dbo.udf_get_book_ISBN(xCol)
 
  可以用通常的方式将计算列编入索引。


  示例:基于XML数据类型方法的计算列上的查询


  要获取其ISBN为 0-7356-1588-2 的 ,可以改写XML列上的查询


  select xCol
  FROM   T
  where  xCol.exist (’/book[@ISBN = “0-7356-1588-2”]’) =1
 
  以使用计算列,如下所示:


  select xCol
  FROM   T
  where  ISBN = ’0-7356-1588-2’
 
  可以创建一个用户定义的函数,返回XML数据类型和使用该UDF的计算列。然而,无法在计算的XML列上创建XML索引。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

电子邮件地址不会被公开。 必填项已用*标注

敬请读者发表评论,本站保留删除与本文无关和不雅评论的权力。

相关推荐

  • 数据库设计需做好前期工作 Agile方法不适合

    有很多企业认为数据建模以及设计良好的数据库是浪费时间的工作,对此专家的回答很直接:决不能忽视数据库设计过程。

  • SAP HANA数据建模秘籍

    SAP HANA是一个全新的数据库平台,它提供了全新的数据建模方式,使得传统关系型数据库管理系统(RDBMS)得到了进一步的扩展。

  • 介绍PostgreSQL的数组类型

    PostgreSQL 有很多丰富的开箱即用的数据类型,从标准的数字数据类型、到几何类型,甚至网络数据类型等等。

  • Redis sds数据结构实现分析

    sds(Simple Dynamic Strings)是Redis中最基本的底层数据结构, 它既是Redis的String类型的底层实现,也是实现Hash、List和Set等复合类型的基石。