【问题标题】:SQL Server XML shredding performanceSQL Server XML 粉碎性能
【发布时间】:2012-07-15 00:59:24
【问题描述】:

我正在使用 NOAA 当前的观察 XML(例如:Washington DC)并将 4000 多个站点的文件切碎到 SQL Server 2008 R2 表中。在尝试了许多不同的方法之后,我有了一个正在推进的方法。

这个问题是关于不同方法之间的性能,最重要的是为什么它如此激烈。

第一次尝试

在 C# 中工作我使用 Linq to XML 解析所有文件,并使用 Linq to SQL 将结果记录写入数据库。这个代码是可预测的,所以我不会让你厌烦。

用 linq 重写到实体框架没有帮助。

这导致应用程序运行了一个多小时,并且只处理了 1600 个左右的文件。缓慢是 Linq to SQL 和 Linq to Entities 为每条记录执行插入和选择的结果。

第二次尝试

我仍在使用 C# 工作,我试图通过使用在线提供的批量插入方法来加速它(例如:Speeding up inserts using Linq-to-SQL - Part 1)。

虽然比第一次尝试明显快,但仍然很慢。

此时,我转而使用存储过程来处理 XML 粉碎和插入,使用 C# 代码将文件连接成一个 XML 字符串并添加一个包装器标记。

第三次尝试

使用类似这样的 SQL Server 的 XML 查询(@xml 是 xml 文件)[记忆中]:

select credit = T.observation.value('credit[1]', 'varchar(256)')
       ,... -- the rest of the elements possible in the file.
from @xml.nodes('wrapper') W(station)
    cross apply W.station.nodes('current_observation') T(observation)

我让它运行了 15 分钟,然后取消,处理了大约 250 条记录。

第四次尝试

我将查询更改为使用 OpenXML:

declare $idoc int

exec sp_xml_preparedocument @idoc output, @xml

select Credit
       ,... -- the rest of the elements
from openxml(@idoc, '/wrapper/current_observations', 2)
    with (
        Credit varchar(256) 'credit'
        ,...) -- the rest of the elements

exec sp_xml_removedocument @idoc

这在 10 秒内处理了所有 4000 多条记录!完全可以接受。

虽然我预计这些方法之间会有一些差异,但我没想到差异会如此显着。

所以我的问题很简单,

'为什么不同方法之间的性能差异如此之大?'

我很高兴被证明我使用了前 3 个错误。

【问题讨论】:

    标签: xml performance sql-server-2008-r2


    【解决方案1】:

    可能能够为加快 XQuery 选项做的一件事是避免交叉连接。

    我看不到您的 XML 是什么样子 - 华盛顿特区示例只包含一个节点 - 但假设 XML 只包含一个 <wrapper> 和其中的 <current_observation> 列表,那么您可以优化您的要读取的 XQuery:

    select 
        credit = T.observation.value('credit[1]', 'varchar(256)')
        ,... -- the rest of the elements possible in the file.
    from 
        @xml.nodes('wrapper/current_observation') T(observation)
    

    这应该比您在测试中看到的速度快很多。

    如果您有时间尝试这个 - 我最想知道这种修改后的方法如何叠加 - 与您原来的 XQUery 和 OPENXML 解决方案相比。

    【讨论】:

    • 是的,我正在从每个文件中提取 current_observation 节点,并将它们与围绕它们的 元素连接起来。
    • 我以为我已经尝试在没有交叉应用的情况下引用 current_observation 标记,但显然不是。我使用您建议的更改重新运行测试,正如您所料,时间要快得多。处理 4000 多个 current_observation 元素需要 43 秒。虽然它仍然花费了 4 倍的时间,但它在同一个社区,并解释了为什么之前的差异如此之大。
    【解决方案2】:

    您能否确认您没有在查询中使用父轴(“..”)?这会破坏性能。您还可以添加 text() 访问器,这也应该可以提高性能,如下所示:

    select
    o.c.value('(credit/text())[1]', 'varchar(max)'),
    --...
    from @xml.nodes('wrapper/current_observation') o(c)
    

    【讨论】:

    • 我没有使用父轴。
    【解决方案3】:

    您是否尝试过文本访问器?相对于其中包含 4,096 条记录的 6MB xml 文件,我的 repro 改进了 15-20%,尽管这仅适用于无类型的 XML(SQL Server 中没有关联的 XSD)。

    我还发现我的查询在 10 到 12 秒内运行,所以我仍然对您的 43 秒感到有些困惑。您使用的是什么版本/服务包的 SQL Server?我记得在 SQL 2005 中插入表变量时曾经出现过问题,但认为这已解决。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多