.NET OpenXML的性能问题(.NET OpenXML performance issues)

2019-07-29 08:44发布

我试图写出来的使用的OpenXML的ASP.NET Web服务器的Excel文件。 我有大约2100条记录,并考虑其约20-30秒,以做到这一点。 什么办法可以使其更快? 从数据库中检索2100行需要一秒钟的小部分。 不知道为什么在内存中操纵他们会采取任何更长的时间。

注:ExcelWriter是我们的自定义类,但其所有的方法都是直接从代码在这个环节上, http://msdn.microsoft.com/en-us/library/cc861607.aspx

   public static MemoryStream CreateThingReport(List<Thing> things, MemoryStream template)
    {
        SpreadsheetDocument spreadsheet = SpreadsheetDocument.Open(template, true);
        WorksheetPart workSheetPart = spreadsheet.WorkbookPart.WorksheetParts.First();

        SharedStringTablePart sharedStringPart = spreadsheet.WorkbookPart.GetPartsOfType<SharedStringTablePart>().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>(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>(CellValues.SharedString);

  rowOffset++; 
   }

 workSheetPart.Worksheet.Save();

        spreadsheet.WorkbookPart.Workbook.Save();
        spreadsheet.Close();

        return template;

Answer 1:

所以它看起来像有人在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>(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>(CellValues.String);

MSDN文档(慢的解决方案,就应该使用一个哈希表来代替)

      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<SharedStringItem>())
{
    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;
 }  


Answer 2:

@互联网

需要注意的是String数据类型实际上是公式,文本应使用InlineString。 见17.18.11 ST_CellType(细胞类型):

  • inlineStr(联字符串) - 含有(内联)富细胞串,即,一个不能在共享字符串表。 如果使用这种细胞类型,则该信元值是在IS元件,而不是在单元(C元件)的V族元素。
  • STR(字符串) - 含有一个公式字符串细胞。


Answer 3:

大improment更保存()函数退出循环

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

对于500分的记录,这对我来说改变从10分钟到1分钟。



Answer 4:

@kunjee

如果你想表现前期创建所有必需的对象,以便不检查这种方法的每次调用。 这就是为什么SharedStringTable传入的参数,而不是一部分。

字典是快速,索引查找,比for循环更好的性能。 比哈希表,因为是强类型的,所以不要要求拳击有点快。 被强类型是一个很大的好处呢。

private static int InsertSharedStringItem(string sharedString, SharedStringTable sharedStringTable, Dictionary<string, int> 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;
}


文章来源: .NET OpenXML performance issues