Вопрос по c#, .net, openxml, asp.net-mvc-3, openxml-sdk – Проблемы производительности .NET OpenXML
Я пытаюсь записать файл Excel с веб-сервера ASP.NET, используя OpenXML. У меня около 2100 записей, и на это уходит около 20-30 секунд. В любом случае, я могу сделать это быстрее? Извлечение 2100 строк из БД занимает доли секунды. Не уверен, почему манипулирование ими в памяти займет больше времени.
Примечание. ExcelWriter - это наш пользовательский класс, но все его методы взяты непосредственно из кода по этой ссылке,http://msdn.microsoft.com/en-us/library/cc861607.aspx
<code> 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; </code>
@Интернет
Обратите внимание, что тип данных String фактически предназначен для формул, для текста следует использовать InlineString. См. 17.18.11 ST_CellType (Тип ячейки):
inlineStr (Inline String) - Cell containing an (inline) rich string, i.e., one not in the shared string table. If this cell type is used, then the cell value is in the is element rather than the v element in the cell (c element). str (String) - Cell containing a formula string.Если вы хотите повысить производительность, создайте все необходимые объекты заранее, чтобы они не проверялись при каждом вызове этого метода. Вот почему 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;
}
что кто-то из документации сообщества 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;
}