我正在使用NOAA当前的观察XML(例如:Washington DC),并将4000多个站点的文件粉碎成SQL Server 2008 R2表。在尝试了许多不同的方法后,我有一个我正在前进的方法。
这个问题是关于不同方法之间的表现,最重要的是为什么它如此激烈。
首次尝试
使用C#解析所有使用Linq到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个错误。
答案 0 :(得分:2)
可能能够加快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
解决方案。
答案 1 :(得分:1)
您可以确认在查询中没有使用父轴('..')吗?这可能会破坏性能。您还可以添加text()访问器,这也应该提高性能,如下所示:
select
o.c.value('(credit/text())[1]', 'varchar(max)'),
--...
from @xml.nodes('wrapper/current_observation') o(c)
答案 2 :(得分:0)
您是否尝试过文本存取器?我的repro对一个包含4,096条记录的6MB xml文件有15-20%的改进,尽管这只适用于非类型化的XML(在SQL Server中没有关联的XSD)。
我还发现我的查询在10-12秒内运行,所以你的43秒仍然有些神秘。您使用的SQL Server版本/服务包是什么?我记得在插入表变量时,SQL 2005中曾经存在一个问题,但认为这是固定的。