2012-05-10 17 views
7

Ja próbuje napisać plik Excel z serwera WWW ASP.NET przy użyciu OpenXML. Mam około 2100 rekordów i zajmuje to około 20-30 sekund. W jaki sposób mogę to przyspieszyć? Pobieranie 2100 wierszy z bazy danych zajmuje ułamek sekundy. Nie wiem, dlaczego manipulowanie nimi w pamięci wymagałoby więcej czasu.wydajność NET OpenXML wystawia

Uwaga: ExcelWriter jest nasz zwyczaj klasy, ale wszystkie jej metody są bezpośrednio z kodu w ten 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; 

Odpowiedz

7

Tak to wygląda jakby ktoś w docs społeczności MSDN prowadził do podobnych skutków działania. Poniższy kod jest bardzo nieefektywny. Ktoś polecił użycie tabeli mieszania.

Dla naszego rozwiązania po prostu usunął wprowadzenie wspólnych ciągów całkowicie i poszedł od 1:03 do 0:03 sekund sekund w czasie pobierania.

//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 (powolny rozwiązanie, powinny one korzystać z tabeli mieszania zamiast)

 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

Mam do czynienia z tym samym problemem ... Muszę napisać 1000 wierszy, aw niektórych przypadkach 10000 wierszy i robi się powoli jak cholera ... Tutaj powiedziałeś, że możesz użyć tabeli mieszania możesz podać przykład jak? lub jakakolwiek inna rzecz, której użyłeś do poprawy wydajności ... – kunjee

+0

Patrzę na wiersze 500K. Czy wprowadziłeś inne ulepszenia od tego wpisu, który możesz udostępnić? Przejdę do metody SAX, aby zminimalizować wykorzystanie pamięci. I widzę około 1000 rzędów na ~ 1,1 sekundy. Jeśli pojawi się szybciej niż to, proszę udostępnij. – CaptainBli

2

@kunjee

Jeśli chcesz wydajność tworzenia wszystkich wymaganych przedmiotów góry tak, że nie są sprawdzane na każdym wywołanie tej metody. To dlatego SharedStringTable jest przekazywana jako parametr zamiast części.

Słowniki są do szybkiego i indeksowane odnośnika, mają lepszą wydajność niż pętli for. Są nieco szybciej niż hashtables ponieważ są silnie wpisane więc nie wymagają boks. Bycie silnie wpisanym to i tak wielka korzyść.

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

Zauważ, że String typ danych jest rzeczywiście dla formuł na tekst powinien używać InlineString. See 17.18.11 ST_CellType (typ komórkowy):

  • inlineStr (Inline String) - komórka zawierająca (inline) bogaty ciąg, to znaczy, nie we wspólnym stole strun. Jeśli ten typ komórki jest używany, , wówczas wartość komórki znajduje się w elemencie is, a nie w elemencie v w komórce (element c).
  • ul (ciąg) - komórka zawierająca ciąg wzoru.
2

Dużą improment jest bardziej funkcja Save() z pętli

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

Do 500 rekordów, dla mnie to zmienić od 10 minut do 1 min.

+0

To jest naprawdę ważna część pracy z OpenXML - ponieważ wiele podelementów wymaga zapisu, mamy tendencję do umieszczania zapisu wewnątrz pojedynczych metod działania lub pętli zamiast w zewnętrznym zakresie, w którym zapis jest bardziej wydajny. –

Powiązane problemy