我有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(); } }
因此,它可以在所有文件上正常工作,除了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); } }
解决方法
看起来你每次都在重复读取XML文件,每次使用SimpleStreamAxis中的from p,你都会重新读取并扫描到文件中.同样通过调用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,xml.ToString()); //if the maximum count is set,only load the maximum (in one page) if (maximumCount != 0) break; current++; full = full.Skip(pageSize); }
请注意,这是未经测试的,但您应该希望得到这个想法.您需要避免多次枚举文件,像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,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,xml.ToString()); }