2012-05-10 5 views
7

Ich versuche, eine Excel-Datei von einem ASP.NET-Webserver mit OpenXML zu schreiben. Ich habe ungefähr 2100 Aufzeichnungen und es dauert ungefähr 20-30 Sekunden, um dies zu tun. Irgendwie kann ich es schneller machen? Das Abrufen der 2100 Zeilen aus der Datenbank dauert einen Bruchteil einer Sekunde. Nicht sicher, warum das Manipulieren in der Erinnerung länger dauern würde..NET OpenXML-Leistungsprobleme

Hinweis: ExcelWriter ist unsere eigene Klasse, aber alle seine Methoden sind direkt aus dem Code in diesem Link, 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; 

Antwort

7

So sieht es aus wie jemand in der MSDN Community docs lief in ähnliche Auswirkungen auf die Leistung. Der folgende Code ist sehr ineffizient. Jemand hat empfohlen, eine Hash-Tabelle zu verwenden.

Für unsere Lösung haben wir nur das Einfügen von gemeinsamen Strings komplett entfernt und ging von 1:03 Sekunden auf 0:03 Sekunden in Download-Zeit.

//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 Docs (langsame Lösung, sollten sie eine Hash-Tabelle verwenden, anstatt)

 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; 
} 
+0

Ich habe das gleiche Problem ... Ich muss mehr als 1000 Zeilen und in einigen Fällen mehr als 10000 Zeilen schreiben und es wird langsam wie die Hölle ... Hier sagten Sie, Sie können Hash-Tabelle verwenden können Sie ein Beispiel geben, wie? oder wenn Sie etwas anderes verwenden, um die Leistung zu verbessern ... – kunjee

+0

Ich suche 500K Zeilen. Hast du weitere Verbesserungen vorgenommen, seit du diesen Beitrag teilen kannst? Ich bin zur SAX-Methode gewechselt, um die Speichernutzung zu minimieren. Und ich sehe ungefähr 1000 Zeilen pro ~ 1,1 Sekunden. Wenn Sie schneller als dies bitte teilen. – CaptainBli

2

@kunjee

Wenn Sie die Leistung im Voraus alle erforderlichen Objekte erstellt werden soll, so dass nicht auf jedem geprüft Aufruf dieser Methode. Aus diesem Grund wird SharedStringTable als Parameter anstelle des Teils übergeben.

Wörterbücher sind für schnelle, indizierte Suche, haben eine bessere Leistung als eine for-Schleife. Sind etwas schneller als Hashtabellen, da sie stark typisiert sind und kein Boxing erfordern. Stark typisiert zu sein, ist sowieso ein großer Vorteil.

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; 
} 
4

@The Internet

Beachten Sie, dass String-Datentyp tatsächlich für Formeln ist, für Text InlineString verwenden sollten. Siehe 17.18.11 ST_CellType (Zellentyp):

  • inlineStr (Inline-String) - Zelle, die eine (Inline) reiche Schnur, das heißt, man nicht in der gemeinsamen String-Tabelle. Wenn dieser Zelltyp verwendet wird, ist der Zellenwert im Element is und nicht das Element v in die Zelle (c-Element).
  • str (String) - Zelle mit einer Formelzeichenfolge.
2

Der große improment ist mehr Save() Funktion aus Schleife

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

Für 500 Datensätze, für mich ist es von 10 Minuten bis 1 min ändern.

+0

Dies ist ein wirklich wichtiger Teil der Arbeit mit OpenXML - da viele der Unterparts einen Speichervorgang erfordern, neigen wir dazu, den Speicher in singuläre Aktionsmethoden oder -schleifen zu setzen, anstatt in den äußeren Bereich, wo der Speicher leistungsfähiger ist. –