Вопрос по c#, .net, openxml, asp.net-mvc-3, openxml-sdk – Проблемы производительности .NET OpenXML

9

Я пытаюсь записать файл 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>

Ваш Ответ

4   ответа
3

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

Для 500 записей для меня это изменение с 10 минут до 1 минуты.

Это действительно важная часть работы с OpenXML - поскольку многие части требуют сохранения, мы склонны помещать сохранение внутри отдельных методов или циклов действия, а не во внешнюю область, где сохранение более производительно.
Удаление лишних «Сохранить ()» вызовы действительно повысили производительность, но я обнаружил, что полностью обошел Таблицу общих строк и сохранил весь текст как «InLineString». Быть самым быстрым за пару тысяч строк. От трех часов до минуты.
5

@Интернет

Обратите внимание, что тип данных 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.
2

Если вы хотите повысить производительность, создайте все необходимые объекты заранее, чтобы они не проверялись при каждом вызове этого метода. Вот почему 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;
}
7

что кто-то из документации сообщества 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;
 }  
Я сталкиваюсь с той же проблемой ... Мне нужно написать более 1000 строк, а в некоторых случаях более 10000 строк, и это становится чертовски медленным ... Здесь вы сказали, что можете использовать хеш-таблицу. Можете привести пример, как? или если что-то еще вы использовали для улучшения производительности ...
Я смотрю на 500 тыс. Строк. Вы внесли другие улучшения после публикации этой статьи? Я перешел на метод SAX, чтобы минимизировать использование памяти. И я вижу около 1000 строк за ~ 1,1 секунды. Если вы получаете быстрее, чем это, пожалуйста, поделитесь.

Похожие вопросы