2014-07-16 2 views
4

xlsx에 쓰는 SAX 메서드의 성능을 향상 시키려고했습니다. 엑셀에는 1048576 행의 제한이 있다는 것을 알고 있습니다. 나는이 한계를 단지 몇 번 명중했다. 대부분의 경우 125K에서 250K 행 (큰 데이터 세트) 만 작성합니다. 내가 시도한 코드는 파일에 여러 번 쓰기 때문에 가능한 빠를 것 같지 않습니다. 일부 캐싱이 포함되기를 바랄 것이지만, 코드가 작동하는 방식에 너무 많은 디스크 액세스가있는 것처럼 보입니다.Excel로 100K + 행을 빠르게 내보내는 OpenXML Sax 메서드

아래 코드는 ClosedXML을 사용하여 파일에 기록한 다음 큰 콘텐츠를 SAX로 전환했기 때문에 Using a template with OpenXML and SAX과 유사합니다. 이 많은 행에 ClosedXML을 사용하려고하면 메모리가 차트에서 사라집니다. 그래서 SAX를 사용하고 있습니다.

 int numCols = dt.Columns.Count; 
     int rowCnt = 0; 
     //for (curRec = 0; curRec < totalRecs; curRec++) 
     foreach (DataRow row in dt.Rows) 
     { 
      Row xlr = new Row(); 

      //starting of new row. 
      //writer.WriteStartElement(xlr); 

      for (int col = 0; col < numCols; ++col) 
      { 
       Cell cell = new Cell(); 
       CellValue v = new CellValue(row[col].ToString()); 

       { 
        string objDataType = row[col].GetType().ToString(); 
        if (objDataType.Contains(TypeCode.Int32.ToString()) || objDataType.Contains(TypeCode.Int64.ToString())) 
        { 
         cell.DataType = new EnumValue<CellValues>(CellValues.Number); 
         //cell.CellValue = new CellValue(row[col].ToString()); 
         cell.Append(v); 
        } 
        else if (objDataType.Contains(TypeCode.Decimal.ToString()) || objDataType.Contains("Single")) 
        { 
         cell.DataType = new EnumValue<CellValues>(CellValues.Number); 
         cell.Append(v); 
         //TODO: set the decimal qualifier - May be fixed elsewhere 
         cell.StyleIndex = 2; 
        } 
        else 
        { 
         //Add text to text cell 
         cell.DataType = new EnumValue<CellValues>(CellValues.String); 
         cell.Append(v); 
        } 
       } 

       if (colStyles != null && col < colStyles.Count) 
       { 
        cell.StyleIndex = (UInt32Value)colStyles[col]; 
       } 

       //writer.WriteElement(cell); 
       xlr.Append(cell); 
      } 
      writer.WriteElement(xlr); 
      //end row element 
      //writer.WriteEndElement(); 
      ++rowCnt; 
     } 

이 코드는 내가 본 일부 예제와 매우 비슷합니다. 그러나 문제는 아직도 느리다는 것이다. 개별 셀 쓰기에서 행 추가 및 행 쓰기로 변경하면 125K 행에서 10 % 씩 프로세스가 향상되었습니다.

글쓴이를 개선하거나 글을 쓰는 방법을 발견 한 사람이 있습니까? 이 프로세스를 가속화 할 수있는 방법이 있습니까?

성능을 향상시키기 위해 캐싱을 설정하려는 사람이 있습니까?

답변

5

일반적인 문제는 DOM과 SAX 메서드를 함께 사용하지 않아야한다는 것입니다. 일단 이들을 혼합하면 성능은 DOM을 사용하는 것과 유사합니다. 당신이 모든에 갈 때 SAX의 성능 이점이 일이 먼저 질문에 대답하려면.

사람이 작가 또는 설치 적은 시간을 쓸 수있는 방법을 개선 할 수있는 방법을 발견 했습니까? 이 프로세스를 가속화 할 수있는 방법이 있습니까?

DOM 조작으로 SAX 작성기를 혼합하지 마십시오. 즉, SDK 클래스 속성이나 함수를 전혀 조작하지 않아야합니다. 그래서 cell.Append()가 종료되었습니다. 그래서 cell.DataType 또는 cell.StyleIndex입니다. 당신이 SAX 작업을 수행 할 때

, 당신은 모든 이동 (즉 ... 약간 자극적 인 소리) 예를 들면 다음과 같습니다.

옥사가 목록과 oxw는 SAX 작가 클래스 OpenXmlWriter입니다
for (int i = 1; i <= 50000; ++i) 
{ 
    oxa = new List<OpenXmlAttribute>(); 
    // this is the row index 
    oxa.Add(new OpenXmlAttribute("r", null, i.ToString())); 

    oxw.WriteStartElement(new Row(), oxa); 

    for (int j = 1; j <= 100; ++j) 
    { 
     oxa = new List<OpenXmlAttribute>(); 
     // this is the data type ("t"), with CellValues.String ("str") 
     oxa.Add(new OpenXmlAttribute("t", null, "str")); 

     // it's suggested you also have the cell reference, but 
     // you'll have to calculate the correct cell reference yourself. 
     // Here's an example: 
     //oxa.Add(new OpenXmlAttribute("r", null, "A1")); 

     oxw.WriteStartElement(new Cell(), oxa); 

     oxw.WriteElement(new CellValue(string.Format("R{0}C{1}", i, j))); 

     // this is for Cell 
     oxw.WriteEndElement(); 
    } 

    // this is for Row 
    oxw.WriteEndElement(); 
} 

. 내 기사에 대한 자세한 내용은 here입니다.

SAX 작업을 캐시하는 실제 방법은 없습니다. 그것들은 일련의 printf 문장과 같습니다. 예를 들어 완전한 Cell 클래스를 작성하기 위해 청크에 WriteStartElement(), WriteElement() 및 WriteEndElement() 함수를 수행하는 도우미 함수를 작성할 수 있습니다.

+0

나는 Google 검색에서 발견 된 SAX의 많은 예를 따라 왔습니다. 어떤 이유로 SAX와 DOM이 혼합되어 있습니다. 나는 곧 당신의 해결책을 시도 할 것입니다. – CaptainBli

+0

좋은 시작입니다. 개선 효과는 약 20 %입니다. 125000 행과 44 열에 대한 테스트를 실시했습니다. 완료까지 100 초 이상 걸렸습니다. 125 초가 넘었던 곳입니다. – CaptainBli

+1

그래서 DOM에 대한 다른 참조를 발견하고 특정 코드 (if 문 및 우선 순위 지정)에 몇 가지 다른 알고리즘 개선 사항을 발견했습니다. 이제 47 개에 125K 행이 있습니다.100 초 또는 125 초 대신 3 초. 밀리 세컨드마다 여러 번 반복 할 때 중요합니다. – CaptainBli

0
 using (var stream = new MemoryStream()) 
      { 
       // ok, we can run the real code of the sample now 
       using (var xlPackage = new ExcelPackage(stream)) 
       { 
        // get handles to the worksheets 
        var worksheet = xlPackage.Workbook.Worksheets.Add("SheetName"); 
        worksheet.Cells["A1"].LoadFromCollection(itemsToExport, true, TableStyles.Medium15); 
        xlPackage.Save(); 
       } 

다음은 EPPlus dll로 몇 초 만에 1000K 행을 생성하는 데 도움이됩니다.

+0

EPPlus dll이란 무엇입니까? itemToExport에는 무엇이 포함되어 있습니까? – CaptainBli

+0

여기를 클릭하면 멋진 설명을 얻을 수 있습니다. https://stackoverflow.com/questions/37902846/epplus-example-of-loadfromcollectiontienumerable-- boolean-tablestyles-b –