.NET OpenXML性能问题

我试图使用OpenXML从ASP.NET Web服务器写出一个Excel文件。 我有大约2100条记录,大约需要20-30秒才能完成。 我能以任何方式加快速度吗? 从db中检索2100行只需要几分之一秒。 不确定为什么在内存中操作它们会花费更长的时间。

注意:ExcelWriter是我们的自定义类,但它的所有方法都直接来自此链接中的代码, http://msdn.microsoft.com/en-us/library/cc861607.aspx

public static MemoryStream CreateThingReport(List things, MemoryStream template) { SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(template, true); WorksheetPart workSheetPart = spreadsheet.WorkbookPart.WorksheetParts.First(); SharedStringTablePart sharedStringPart = spreadsheet.WorkbookPart.GetPartsOfType().First(); Cell cell = null; int index = 0; //create cell formatting for header text Alignment wrappedAlignment = new Alignment { WrapText = true }; uint rowOffset = 2; foreach (Thing t in things) { //Received Date cell = ExcelWriter.InsertCellIntoWorksheet("A", rowOffset, workSheetPart); index = ExcelWriter.InsertSharedStringItem(t.CreateDate.ToShortDateString(), sharedStringPart); cell.CellValue = new CellValue(index.ToString()); cell.DataType = new DocumentFormat.OpenXml.EnumValue(CellValues.SharedString); //Car Part Name cell = ExcelWriter.InsertCellIntoWorksheet("B", rowOffset, workSheetPart); index = ExcelWriter.InsertSharedStringItem(t.CarPart.Name, sharedStringPart); cell.CellValue = new CellValue(index.ToString()); cell.DataType = new DocumentFormat.OpenXml.EnumValue(CellValues.SharedString); rowOffset++; } workSheetPart.Worksheet.Save(); spreadsheet.WorkbookPart.Workbook.Save(); spreadsheet.Close(); return template; 

因此,看起来MSDN社区文档中的某些人遇到了类似的性能影响。 下面的代码非常低效。 有人建议使用哈希表。

对于我们的解决方案,我们只是完全删除了共享字符串的插入,并在下载时间从1:03秒到0:03秒。

 //Old: (1:03) cell = ExcelWriter.InsertCellIntoWorksheet("A", rowOffset, workSheetPart); index = ExcelWriter.InsertSharedStringItem(thing.CreateDate.ToShortDateString(), sharedStringPart); cell.CellValue = new CellValue(index.ToString()); cell.DataType = new DocumentFormat.OpenXml.EnumValue(CellValues.SharedString); //New: (0:03) cell = ExcelWriter.InsertCellIntoWorksheet("A", rowOffset, workSheetPart); cell.CellValue = new CellValue(thing.CreateDate.ToShortDateString()); cell.DataType = new DocumentFormat.OpenXml.EnumValue(CellValues.String); 

MSDN Docs(缓慢的解决方案,他们应该使用哈希表)

  private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart) { // If the part does not contain a SharedStringTable, create one. if (shareStringPart.SharedStringTable == null) { shareStringPart.SharedStringTable = new SharedStringTable(); } int i = 0; // Iterate through all the items in the SharedStringTable. If the text already exists, return its index. foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements()) { if (item.InnerText == text) { return i; } i++; } // The text does not exist in the part. Create the SharedStringItem and return its index. shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text))); shareStringPart.SharedStringTable.Save(); return i; } 

@互联网

请注意,String数据类型实际上是用于公式,因为文本应该使用InlineString。 请参见17.18.11 ST_CellType(单元格类型):

  • inlineStr(内联字符串) – 包含(内联)丰富字符串的单元格,即不在共享字符串表中的字符串。 如果使用此单元格类型,则单元格值位于is元素而不是单元格中的v元素(c元素)。
  • str(String) – 包含公式字符串的单元格。

最大的改进是更多Save()函数退出循环

  //Save data shareStringPart.SharedStringTable.Save(); worksheetPart.Worksheet.Save(); 

对于500条记录,对我而言,它从10分钟变为1分钟。

@kunjee

如果您希望性能预先创建所有必需的对象,则不会在每次调用此方法时进行检查。 这就是为什么SharedStringTable作为参数而不是部件传入的原因。

字典用于快速索引查找,具有比for循环更好的性能。 比哈希表更快,因为是强类型,所以不需要拳击。 无论如何,强烈打字是一个很大的好处。

 private static int InsertSharedStringItem(string sharedString, SharedStringTable sharedStringTable, Dictionary sharedStrings) { int sharedStringIndex; if (!sharedStrings.TryGetValue(sharedString, out sharedStringIndex)) { // The text does not exist in the part. Create the SharedStringItem now. sharedStringTable.AppendChild(new SharedStringItem(new Text(sharedString))); sharedStringIndex = sharedStrings.Count; sharedStrings.Add(sharedString, sharedStringIndex); } return sharedStringIndex; }