Jos*_*osh 6 c# xml performance file large-files
我有16个大的xml文件.当我说Large时,我说的是千兆字节.其中一个文件超过8 GB.其中一些超过1 GB.这些是从外部提供商处获得的.
我试图将XML导入数据库,以便我可以将其粉碎成表.目前,我一次将10,000条记录从文件中流入内存并插入blob.我使用SSIS执行脚本任务.对于除8 GB文件之外的所有文件,这实际上非常快.
我无法将整个文件加载到xml文档中.我不能强调这一点.这是迭代1,文件非常庞大,系统只是锁定试图处理这些文件,特别是8 GB.
我运行了当前的"文件分割器",它花了7个小时来导入xml数据,但仍未完成.它从8 GB文件中导入了363个10,000个记录的块,但仍未完成.
仅供参考,以下是我目前将文件流式传输到内存中的方法(一次10,000条记录).我在http://blogs.msdn.com/b/xmlteam/archive/2007/03/24/streaming-with-linq-to-xml-part-2.aspx找到了代码
private static IEnumerable<XElement> SimpleStreamAxis(string fileName, string matchName)
{
using (FileStream stream = File.OpenRead(fileName))
{
using (XmlReader reader = XmlReader.Create(stream, new XmlReaderSettings() { ProhibitDtd = false }))
{
reader.MoveToContent();
while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == matchName)
{
XElement el = XElement.ReadFrom(reader) as XElement;
if (el != null)
yield return el;
}
break;
}
}
reader.Close();
}
stream.Close();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,它可以在所有文件上正常工作,除了8 GB之外,因为它必须进一步流入文件所需的时间越来越长.
我想要做的是将文件拆分成更小的块,但拆分器需要快速.然后流光和其余的流程可以更快地运行.分割文件的最佳方法是什么?理想情况下,我自己将其拆分为SSIS中的代码.
编辑:
这是使用流式处理方法实际分页我的数据的代码.
connection = (SqlConnection)cm.AcquireConnection(null);
int maximumCount = Convert.ToInt32(Dts.Variables["MaximumProductsPerFile"].Value);
int minMBSize = Convert.ToInt32(Dts.Variables["MinimumMBSize"].Value);
int maxMBSize = Convert.ToInt32(Dts.Variables["MaximumMBSize"].Value);
string fileName = Dts.Variables["XmlFileName"].Value.ToString();
FileInfo info = new FileInfo(fileName);
long fileMBSize = info.Length / 1048576; //1024 * 1024 bytes in a MB
if (minMBSize <= fileMBSize && maxMBSize >= fileMBSize)
{
int pageSize = 10000; //do 2000 products at one time
if (maximumCount != 0)
pageSize = maximumCount;
var page = (from p in SimpleStreamAxis(fileName, "product") select p).Take(pageSize);
int current = 0;
while (page.Count() > 0)
{
XElement xml = new XElement("catalog",
from p in page
select p);
SubmitXml(connection, fileName, xml.ToString());
//if the maximum count is set, only load the maximum (in one page)
if (maximumCount != 0)
break;
current++;
page = (from p in SimpleStreamAxis(fileName, "product") select p).Skip(current * pageSize).Take(pageSize);
}
}
Run Code Online (Sandbox Code Playgroud)
看起来你每次重复读取XML文件的每一步,每次使用from p in SimpleStreamAxis你正在重新读取的位并扫描到文件中.同样通过调用Count(),您每次都会走完整页.
尝试这样的事情:
var full = (from p in SimpleStreamAxis(fileName, "product") select p);
int current = 0;
while (full.Any() > 0)
{
var page = full.Take(pageSize);
XElement xml = new XElement("catalog",
from p in page
select p);
SubmitXml(connection, fileName, xml.ToString());
//if the maximum count is set, only load the maximum (in one page)
if (maximumCount != 0)
break;
current++;
full = full.Skip(pageSize);
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是未经测试的,但您应该希望得到这个想法.您需要避免多次枚举文件,像Count()和Take/Skip这样的操作将花费很长时间在8gb xml文件上.
更新:我认为上面的内容仍然会比我们想要的更多次遍历文件,你需要一些更可预测的东西:
var full = (from p in SimpleStreamAxis(fileName, "product") select p);
int current = 0;
XElement xml = new XElement("catalog");
int pageIndex = 0;
foreach (var element in full)
{
xml.Add(element);
pageIndex++;
if (pageIndex == pageSize)
{
SubmitXml(connection, fileName, xml.ToString());
xml = new XElement("catalog");
pageIndex = 0;
}
//if the maximum count is set, only load the maximum (in one page)
if (maximumCount != 0)
break;
current++;
}
// Submit the remainder
if (xml.Elements().Any())
{
SubmitXml(connection, fileName, xml.ToString());
}
Run Code Online (Sandbox Code Playgroud)