DB2® 9 提供了 pureXML 存储并给出 XQuery 和 SQL/XML 作为查询语言。XML 索引是高查询性能所必需的,但是其在查询评估方面的使用取决于查询谓词的表示方式。本文以一致的方式给出了一组指导原则,用于编写 XML 查询和创建 XML 索引,从而如期加快查询速度。还介绍了需要在 XML 查询执行计划中查找的内容,以便检测性能问题,然后找到解决这些问题的方法。可下载的 “备忘单” 概括了最重要的一些指导原则。
简介
DB2 9 提供了 pureXML 存储以及 XML 索引、作为查询语言的 XQuery 和 SQL/XML、XML 模式支持、对实用程序(如 Import/Export 和 Runstats)的 XML 扩展。正如在关系查询中一样,索引对于高性能的 XQuery 和 SQL/XML 是至关重要的。DB2 允许在 XML 列上定义 path-specific XML 索引。这意味着可以使用它们来索引频繁在谓词和连接中使用的所选择的元素和属性。例如,使用图 1 中的示例数据,基于 author ID,可以使用下面的索引 idx1 对表 books 的 XML 列 bookinfo 中的所有文档进行查找和连接。
create table books(bookinfo XML);
create index idx1 on books(bookinfo) generate keys
using xmlpattern '/book/authors/author/@id' as sql double;
图 1. 以文本(连续)格式和解析(分层)格式表示的示例 XML 文档
由于 DB2 不强制要求将单个 XML 模式与 XML 列中的所有文档相关联,所以特定元素和属性的数据类型事先是未知的。因此,要求为每个 XML 索引指定一个目标类型。稍后,您将在本文了解到为什么类型很重要。可以使用的 XML 索引数据类型如下:
VARCHAR(n):用于带有字符串值的节点,已知字符串值的最大长度为 n。
VARCHAR HASHED:用于带有字符串值的节点,字符串值的长度为任意长度。该索引包含实际字符串的散列值,只能用于等式谓词,不能用于范围谓词。
DOUBLE:用于带有任意数值类型的节点。
DATE and TIMESTAMP:用于带有日期或时间戳值的节点。
VARCHAR(n) 索引的长度是一个强制约束。如果插入一个文档,其中索引元素或属性的值超过了最大长度 n,则插入操作将失败。同样,如果索引元素或属性的值大于 n,则 VARCHAR(n) 索引的 create index 语句将失败。
DOUBLE、DATE 或 TIMESTAMP 索引不是强制约束。例如,将 author ID 属性上的索引 idx1 定义为 DOUBLE,是希望这些 ID 为数值。如果插入一个文档,其中 author ID 的值为 “MN127”,它是非数型值的,则虽然仍将插入该文档,但不会将 “MN127” 值添加到索引。这是因为 DOUBLE 索引只能评估数值谓词,然而 “MN127” 值永远不会匹配一个数值搜索条件。因此,索引中没有该值是正确的。
您可以在 “Indexing XML Documents in DB2”(developerWorks,2006 年 5 月)中找到有关定义 XML 索引的更多详细内容。下面在讨论 XML 索引的使用时,也假定您熟悉查询 DB2 中 XML 数据的基本概念。有关更多信息,请参考以前的文章:“用 SQL 查询 DB2 XML 数据”(developerWorks,2006 年 3 月)和 “使用 XQuery 查询 DB2 XML 数据”(developerWorks,2006 年 4 月)给出了介绍,“DB2 9 中的 pureXML:怎样查询您的 XML 数据?”(developerWorks,2006 年 6 月)给出了更多示例和详细内容。
适合于 XQuery 和 SQL/XML 语句的 XML 索引
正如在关系查询中一样,索引对于高性能的 XQuery 和 SQL/XML 语句是至关重要的。当应用程序向 DB2 提交关系查询或 XML 查询时,查询编译器将比较查询谓词和现有的索引定义,然后确定是否存在可用索引用于执行查询。该过程被称为 “索引匹配”,并且为给定的查询生成一组合适的索引(可能是空集)。将该组索引输入到基于开销的优化器,用来决定是否使用任何合适的索引。本文的专注于索引匹配,而不是优化器的索引选择。在优化器决策方面,除了运行 “runstats” 来为优化器提供关于数据的准确的统计之外,所能做的事情不是很多。但却有大量的工作可以做来确保索引匹配。
在关系查询中,索引匹配通常是微不足道的。DB2 可以使用定义在单个关系列上的索引来响应此列上的任何等式谓词或范围谓词。但是,对于 XML 列,这将更加复杂。关系列上的索引包含了此列的所有值,而 XML 索引仅包含那些同时匹配 XML 模式和索引定义中的数据类型的节点值。因此,仅当 XML 索引拥有 “正确的”数据类型并且至少包含满足谓词的所有 XML 节点时,该 XML 索引才能用于评估 XML 查询谓词。对于 XML 索引的合格性,有两个主要要求:
XML 索引定义的限制等同于或低于查询谓词的限制(“容纳”)。
索引的数据类型与查询谓词的数据类型相匹配。
本文说明了如何设计 XML 索引和查询以确保符合上述要求,以及如何避免常见错误。先从了解查询执行计划开始。DB2 中现有的解释工具(例如 Visual Explain 和 db2exfmt)可用于查看 XQuery 和 SQL/XML 的查询执行计划,正像它们在传统 SQL 中的作用一样。
XML 查询评估:执行计划和新运算符
为了执行 XML 查询,DB2 9 引入了三个新的内部查询操作符,名为 XSCAN、XISCAN 和 XANDOR。这些新操作符和现有的查询操作符(例如 TBSCAN、FETCH 和 SORT)允许 DB2 生成 SQL/XML 和 XQueries 的执行计划。现在看一下这三个新操作符,以及它们与 XML 索引在执行计划中是如何工作的。
XSCAN(XML 文档扫描)
DB2 使用 XSCAN 操作符来遍历 XML 文档树,如需要,还将评估谓词和提取文档片断和值。XSCAN 不是“XML 表扫描”,但在表扫描之后,它可以出现在执行计划中,用来处理每个文档。
XISCAN(XML 索引扫描)
类似于现有的用于关系索引的关系索引扫描操作符 (IXSCAN),XISCAN 操作符在 XML 索引上执行查找或扫描。XISCAN 使用值谓词作为输入,例如类似于 /book[price = 29] 或 where $i/book/price = 29 的路径值对。它将返回一组行 ID 和节点 ID。行 ID 用来识别包含合格文档的行,而节点 ID 用来识别这些文档中的合格节点。
XANDOR (连接 XML 索引)
XANDOR 操作符通过操作多个 XISCAN,来同时评估两个或多个等式谓词。它将返回那些满足所有谓词的文档的行 ID。
下面看一个示例查询,分别了解不带索引、带一个索引和带多个索引的执行计划:
XQUERY
for $i in db2-fn:xmlcolumn("BOOKS.BOOKINFO")
where $i/book/title = "Database systems" and $i/book/price = 29
return $i/book/authors
create index idx1 on books(bookinfo) generate keys
using xmlpattern '/book/title' as sql varchar(50);
create index idx2 on books(bookinfo) generate keys
using xmlpattern '/book/price' as sql double;
在图 2 中可以看到该查询的不同执行计划(简化了 db2exfmt 的输出)。因为执行计划中的逻辑流是自下而上、从左到右,所以看此类执行计划时,最好是从树中左下方的操作符开始。
如果该查询中没有合适的索引用于谓词,则使用最左边的计划 (a)。表扫描操作符 (TBSCAN) 将读取表 “BOOKS” 中的所有行。对于每一行,嵌套循环连接 (NLJOIN) 操作符把指向相应的 XML 文档的指针传递给 XSCAN 操作符。同样地,NLJOIN 并没有充当拥有两个输入的标准连接,而是协助 XSCAN 操作符来访问 XML 数据。XSCAN 操作符将遍历每个文档、评估谓词,如果满足谓词,则提取 “authors” 元素。RETURN 操作符将完成查询执行,并将查型结果返回到 API。
图 2. 三个执行计划:(a) 没有索引、(b) 一个索引、(c) 两个索引
如果有一个索引用于一个或两个谓词,例如 /book/price 上的索引 idx1,则将看到类似于图 2 中计划 (b) 的执行计划。XISCAN 使用路径值对(/book/price,29) 来检查索引,并返回其中价格为 29 的文档的行 ID。对这些行 ID 进行分类,以便删除相同项(如果有),并优化表的后续 I/O。然后行 ID 扫描 (RIDSCN) 操作符将扫描这些行,触发行预取,并将行 ID 传递到 FETCH 操作符。对于每一个行 ID,FETCH 操作符将读取表中相应的行。该计划的好处在于仅对表中的一小部分行进行检索,即仅对 “price” 为 29 的行进行检索。这远远低于全部表扫描(即读取每行)的开销。对于所获取的每一行,XSCAN 操作符将处理相应的 XML 文档。它将在 “title” 上评估谓词,如果满足谓词,则提取 “authors” 元素。可能存在这样一些文档,其中第二个谓词不为真,那么 XSCAN 仍将执行一些操作来排除这些文档。因此,如果第二个谓词也用索引来替代,将会获得更好的查询性能。
如果有用于两个谓词的索引,则可以参看图 2 中的计划 (c)。该计划使用两个 XISCAN,分别用于每一个谓词和索引。XANDOR 操作符使用这些 XISCAN 来轮流检查两个索引,以便有效地找到同时匹配两个谓词的文档的行 ID。FETCH 操作符仅对这些行进行检索,因此将表的 I/O 减到最少。随后对于每一个文档,XSCAN 将提取 “authors” 元素。如果谓词在路径中包括了 // or *,或者