【问题标题】:SQL Server query XML datatype performance issueSQL Server 查询 XML 数据类型性能问题
【发布时间】:2016-12-05 23:37:22
【问题描述】:

我有一个 XML 文件存储在我的表 recordsXML 数据类型列 data 中。

表格如下所示:

create table records 
(
     id int,
     type nvarchar(28),
     data xml,
     posted datetime
)

XML 数据:

<Properties>
    <data>
        <Name>novel</Name>
        <Gender>Female</Gender>
        <Age>32</Age>
        <Salary>55k</Salary>
        <Phone>123-123</Phone>
    </data>
</Properties>

我目前正在使用以下查询从该 XML 列中提取数据,这在 20K 记录中花费了超过几分钟的时间。

select
    id,
    posteddate,
    CONVERT( NVARCHAR(500), data.query('data(Properties/data/Name)') ) AS Name,
    CONVERT( NVARCHAR(500), data.query('data(Properties/data/Gender)') ) AS Gender,
    CONVERT( NVARCHAR(500), data.query('data(Properties/data/Age)') ) AS Age,
    CONVERT( NVARCHAR(500), data.query('data(Properties/data/Salary)') ) AS Salary,
    CONVERT( NVARCHAR(500), data.query('data(Properties/data/Phone)') ) AS Phone
from 
    records
where 
    type = 'personnel_xml'

谁能帮助解释我如何优化这个场景,因为我需要从存储为列的 XML 中提取 100 个这样的元素。

【问题讨论】:

    标签: sql-server xml xquery sql-server-openxml


    【解决方案1】:

    假设您在 XML 中有多个 &lt;data&gt;。请注意,我添加了一个扩展的 XML 文件,其中包含两组。

    Declare @table table (id int,data xml)
    Insert Into @table values (1,'<Properties><data><Name>novel</Name><Gender>Female</Gender><Age>32</Age><Salary>55k</Salary><Phone>123-123</Phone></data>
    <data><Name>Another Name</Name><Gender>Male</Gender><Age>45</Age><Salary>75k</Salary><Phone>555-1212</Phone></data>
    </Properties>')
    
    ;with cte as (
          Select ID
                ,RN   = Row_Number() over (Partition By ID Order By (Select Null))
                ,Data = m.query('.') 
          From   @table AS t
          Cross Apply t.Data.nodes('/Properties/data') AS A(m)
     )
    Select ID
          ,RN
          ,Name   = Data.value('(data/Name)[1]'  ,'nvarchar(500)')
          ,Gender = Data.value('(data/Gender)[1]','nvarchar(500)')
          ,Age    = Data.value('(data/Age)[1]'   ,'nvarchar(500)')
          ,Salary = Data.value('(data/Salary)[1]','nvarchar(500)')
          ,Phone  = Data.value('(data/Phone)[1]' ,'nvarchar(500)')
     From  cte
    

    返回

    ID  RN  Name            Gender  Age     Salary  Phone
    1   1   novel           Female  32      55k     123-123
    1   2   Another Name    Male    45      75k     555-1212
    

    【讨论】:

    • stackoverflow.com/users/1570000/john-cappelletti 我的 xml 有单个数据元素,所以在这种情况下,我希望我不需要交叉应用。那么,从性能的角度来说,应该选择 value() 还是 query() 呢?
    • @JohnCappelleti 在我的 200 年代场景中,“将整个 xml 存储在 #temp 表中并从 #temp 中提取”或“直接从 table.column 中提取而不使用 #temp”在性能上有什么区别元素不重复 属性
    • @LearnByExample 正确,因为您有单个数据元素,因此不需要交叉应用。并且因为您知道路径值会比查询更快。
    • @LearnByExample 关于你的#temp。很难说。一次测试胜过一千个专家意见:)
    【解决方案2】:

    要在 SQL Server 中从 XML 中获取值,您应该使用 value() Method (xml Data Type)。对于无类型的 XML,您应该指定 text() 节点以获得更好的性能。

    select R.id,
           R.posted,
           R.data.value('(/Properties/data/Name/text())[1]', 'nvarchar(500)') as Name,
           R.data.value('(/Properties/data/Gender/text())[1]', 'nvarchar(10)') as Gender,
           R.data.value('(/Properties/data/Age/text())[1]', 'int') as Age,
           R.data.value('(/Properties/data/Salary/text())[1]', 'nvarchar(10)') as Salary,
           R.data.value('(/Properties/data/Phone/text())[1]', 'nvarchar(30)') as Phone
    from dbo.records as R
    where type = N'personnel_xml';
    

    【讨论】:

    • 嗨,你知道吗,如果引擎足够聪明,可以找到,(/Properties/data/ 在所有情况下都是一样的吗?我认为在 CTE 中使用像 John Cappelletti 和 .query() 这样的东西会更快,或者 - 甚至更好 - 在 .nodes(N'/Properties/data') 上使用 CROSS APPLY 然后在 (Name/text())[1] 上使用 .value()。在这种情况下,它不会一遍又一遍地浏览整个 XPath 吗?
    • @Shnugo 嗨,我已经完成了一些关于使用 cross apply nodes 在 values 函数中获得更短表达式的性能测试,而且速度较慢(不多)。使用query() 一点都不好,因为创建新XML 的UDX 运算符会减慢速度。不确定这是否适用于 XML 的 所有 形状和形式,但它适用于我尝试过的所有内容。
    • @Shnugo BTW,即使您使用 cross apply nodes,整个 XML 也可用于值函数。您所拥有的是称为“上下文节点”的东西,它基本上是一个层次 ID,用作值函数的参数。显然,在 XML 的内部表示中使用它而不是路径表达式来查找节点并没有快多少。由于cross apply nodes,至少不会快多少,以补偿额外函数调用的成本。
    • 感谢您的快速回复!我曾想过,使用固定起点(上下文节点)导航会更快...这可能取决于深度和复杂性...当我有一些额外的时间时,我会测试一下。
    • @Shnugo 我唯一关注的是性能。 xml 非常简单,但只有大量元素(近 200 个元素)分隔在 4 个标题元素上,例如 50 元素...50 元素 并且表格行数在 100K 以上。你能推荐一些我可以用来测量/测试运行时间的工具吗?
    猜你喜欢
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多