0

我有一个历史表,其中包含主表的交易记录信息,在该表中我使用 XML 列来存储该交易信息。带有数据的表结构如下所示,

表信息

在内容 XML 数据存储为 XML,如下所示。

        <Answers>
      <AnswerSet>
        <Answer questionId="ProductCode">S3404</Answer>
        <Answer questionId="ProductName">Parabolic Triple</Answer>
        <Answer questionId="LegacyOptionID" selectedvalue="1389">1389</Answer>
        <Answer questionId="LegacyContentID" selectedvalue="624">624</Answer>
        <Answer questionId="LegacyPageID" selectedvalue="355">355</Answer>
        <Answer questionId="LegacyParentID" selectedvalue="760">760</Answer>
     </AnswerSet>
    </Answers>

在所有行中,结构相同,但答案节点中的数据不同,我想获取 ProductCode="S3404" 且 CreatedDate 为新的数据。

我创建了类似的查询

select n2.* from nodehistory n2 CROSS APPLY 
n2.content.nodes('Answers/AnswerSet') T(c) WHERE 
c.value('./Answer[@questionId="ProductCode"][1]','varchar(100)') ='J154'

ProductCode 对每个 nodeid 都有唯一的数据,但是对于同一个 nodeid,这会返回多于一行,因为这是事务表,因此可以多次存储相同的 XML,为此需要像 Createddate desc 的 order 这样的条件,但执行此查询需要我认为由于 XML 处理需要更多时间。

我们可以先得到

Select Top 1 nodeid from NodeHistory order by CreatedDate desc

然后搜索 XML 部分。

关于更合适的视图以获得更好的性能的任何想法?

4

1 回答 1

0

如果您没有对 XML 数据做太多其他事情,那么 .exist 应该比 .value 更有效。我认为 BOL 中有关于此的说明。您还可以使用 sql:variable 使其更通用,例如:

declare @produceCode varchar(20) = 'S3404'

select n2.* 
from nodehistory n2 
    inner join ( select max(id) id from #nodehistory group by nodeId ) maxId ON n2.id = maxId.id
where n2.content.exist('Answers/AnswerSet/Answer[@questionId="ProductCode"][.=sql:variable("@produceCode")]') = 1

我使用子查询将结果集限制为每个 nodeId 的 max(id)。您的要求可能略有不同,但您明白了。

在性能方面,XML 索引可以转换 SQL/XML 查询,但要付出一定的代价。对于存储,您将需要原始表大小的 2-5 倍,因此您必须用数据权衡它。如果您决定使用 XML 索引,那么 PROPERTY 索引应该有助于这种类型的查询,例如

-- create the primary XML index
CREATE PRIMARY XML INDEX xmlidx_nodehistory ON nodehistory(content)
GO

CREATE XML INDEX xmlprpidx_nodehistory ON nodehistory(content)
USING XML INDEX xmlidx_nodehistory FOR PROPERTY
go

declare @produceCode varchar(20) = 'S3404'

select n2.* 
from nodehistory n2 
    inner join ( select max(id) id from nodehistory group by nodeId ) maxId ON n2.id = maxId.id
where n2.content.exist('Answers/AnswerSet/Answer[@questionId="ProductCode"][.=sql:variable("@produceCode")]') = 1

有关更多 SQL XML 性能调优想法,请参阅这些精彩文章:

SQL Server 2005 中 XML 数据类型的性能优化

http://msdn.microsoft.com/en-us/library/ms345118.aspx

SQL Server 2005 中的 XML 索引

http://msdn.microsoft.com/en-us/library/ms345121(SQL.90).aspx

于 2012-09-10T13:59:30.927 回答