2013-04-05 2 views
4

현재 Access 데이터베이스를 XML 파일로 변환하는 중입니다. 이전에이 작업을 수행했지만 이전 프로젝트의 코드가 남아 있습니다. 그러나이 코드를 사용하면 XML을 구조화 할 수 없으므로 이번에는이 작업을 수행해야합니다. 나는 XDocumentfor -loops와 함께 사용하고 있는데,이를 달성하기 위해 1000 행의 데이터를 두 번 처리하면 엄청 느려집니다.왜이 코드가 느려 집니까?

XDocument의 작동 방식을 읽어 보면 XElement.Add은 실제로 전체 XML 코드를 복사하고 모든 요소를 ​​다시 파일에 붙여 넣을 때 새 요소를 추가한다는 것을 알 수 있습니다. 이것이 사실이라면 문제가있는 곳일 것입니다.

이것은 Access에서 Xml로 데이터를 읽고 쓰는 부분으로, 저장하고 저장하는 방법이 있는지 살펴 봅니다. 데이터베이스를 27 개의 열과 12 개의 256 개의 행으로 변환하는 데는 약 30 분이 걸리지 만 작은 500 개의 행으로 구성된 작은 데이터베이스는 약 5 초가 걸립니다.

private void ReadWrite(string file) 
{ 
    using (_Connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;Data Source={0}", pathAccess))) 
    { 
     _Connection.Open(); 
     //Gives me values from the AccessDB: tableName, columnName, colCount, rowCount and listOfTimeStamps. 
     GetValues(pathAccess); 

     XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "true"), new XElement(tableName)); 
     for (int rowInt = 0; rowInt < rowCount; rowInt++) 
     { 
      XElement item = new XElement("Item", new XAttribute("Time", listOfTimestamps[rowInt].ToString().Replace(" ", "_"))); 
      doc.Root.Add(item); 

      //colCount"-1" prevents the timestamp from beeing written again. 
      for (int colInt = 0; colInt < colCount - 1; colInt++) 
      { 
       using (OleDbCommand cmnd = new OleDbCommand(string.Format("SELECT {0} FROM {1} Where TimeStamp = #{2}#", columnName[colInt] , tableName, listOfTimestamps[rowInt]), _Connection)) 
       { 
        XElement value = new XElement(columnName[colInt], cmnd.ExecuteScalar().ToString()); 
        item.Add(value); 
       } 
      } 
      //Updates progressbar 
      backgroundWorker1.ReportProgress(rowInt); 
     } 
     backgroundWorker1.ReportProgress(0); 
     doc.Save(file); 
    } 
} 

이것은 이전 변환기의 코드입니다. 이 코드는 데이터베이스 크기에 거의 영향을받지 않으며 12556 데이터베이스는 변환하는 데 단지 1 초 밖에 걸리지 않습니다. 이 두 가지를 병합하는 방법이있을 수 있습니까?

public void ReadWrite2(string file) 
{ 
    DataSet dataSet = new DataSet(); 
    using (_Connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;Data Source={0}", file))) 
    { 
     _Connection.Open(); 

     DataTable schemaTable = _Connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" }); 

     foreach (DataRow dataTableRow in schemaTable.Rows) 
     { 
      string tableName = dataTableRow["Table_Name"].ToString(); 

      DataTable dataTable = dataSet.Tables.Add(tableName); 
      using (OleDbCommand readRows = new OleDbCommand("SELECT * from " + tableName, _Connection)) 
      { 
       OleDbDataAdapter adapter = new OleDbDataAdapter(readRows); 
       adapter.Fill(dataTable); 
      } 
     } 
    } 
    dataSet.WriteXml(file.Replace(".mdb", ".xml")); 
} 

편집 :이 실행됩니다으로 그냥 명확히하기 위해, 응용 프로그램 속도가 느려집니다. 첫 번째 500 에서처럼 데이터베이스가 아무리 큰지 상관없이 5 초가 걸립니다.

UPDATE : 좋아 내가 지금 다시 주말 이후에 왔어요 내가 읽기와 하나 개의 루프에서 값을 가변 배열을 작성하고 그들을 작성하여 쓰기를 분리해서하는 코드에서 작은 조정을했다 다른. 이것은 나의 이론이 잘못되었다는 것을 증명했으며, 사실 많은 시간을 필요로하는 독서입니다. 루프 내부에서 데이터베이스를 치지 않고 값으로 배열을 채우는 방법에 대한 아이디어가 있습니까?

업데이트 2 : 이것은 DataReader.Read() -loop으로 전환하고 모든 데이터를 즉시 수집 한 결과입니다.

public void ReadWrite3(string Save, string Load) 
    { 
     using (_Connection = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Mode=12;Data Source={0}", Load))) 
     { 
      _Connection.Open(); 
      GetValues(_Connection); 

      _Command = new OleDbCommand(String.Format("SELECT {0} FROM {1}", strColumns, tables), _Connection); 
      XDocument doc = new XDocument(new XDeclaration("1.0", "utf-8", "true"), new XElement("plmslog", new XAttribute("machineid", root))); 
      using (_DataReader = _Command.ExecuteReader()) 
      { 
       for (int rowInt = 0; _DataReader.Read(); rowInt++) 
       { 
        for (int logInt = 0; logInt < colCount; logInt++) 
        { 

         XElement log = new XElement("log"); 
         doc.Root.Add(log); 

         elementValues = updateElementValues(rowInt, logInt); 

         for (int valInt = 0; valInt < elements.Length; valInt++) 
         { 
          XElement value = new XElement(elements[valInt], elementValues[valInt]); 
          log.Add(value); 
         } 
        } 
       } 
      } 
      doc.Save(Save); 
     } 
    } 
+0

병목 현상이 어디 있는지 코드를 프로파일 링 해 보셨습니까? – ChrisBint

+0

@ChrisBint 아니요. 제 3 자 툴이나 소프트웨어없이 그렇게 할 수 있을까요? –

답변

3

나를 용서하십시오. 그러나 나는 당신이 당신의 인생을 그것이 필요로하는 것보다 더 복잡하게 만들고 있다고 생각합니다. OleDbDataReader 개체를 사용하는 경우 데이터 레코드를 열어 배열에서 행 데이터를 캐싱하지 않고도 행을 열어 Access 테이블을 읽을 수 있습니다 (이미 DataReader에 있으므로). 예를 들어

..., 나는 몇 가지 예제 데이터
dbID dbName dbCreated 
---- ------ --------- 
bar  barDB 2013-04-08 14:19:27 
foo  fooDB 2013-04-05 11:23:02 

가 다음과 같은 코드는 ... 테이블을 통해

static void Main(string[] args) 
{ 
    OleDbConnection conn = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Documents and Settings\Administrator\Desktop\Database1.accdb;"); 
    conn.Open(); 

    OleDbCommand cmd = new OleDbCommand("SELECT * FROM myTable", conn); 
    OleDbDataReader rdr = cmd.ExecuteReader(); 

    int rowNumber = 0; 
    while (rdr.Read()) 
    { 
     rowNumber++; 
     Console.WriteLine("Row " + rowNumber.ToString() + ":"); 
     for (int colIdx = 0; colIdx < rdr.FieldCount; colIdx++) 
     { 
      string colName = rdr.GetName(colIdx); 
      Console.WriteLine(" rdr[\"" + colName + "\"]: " + rdr[colName].ToString()); 
     } 
    } 
    rdr.Close(); 
    conn.Close(); 

    Console.WriteLine("Done."); 
} 

를 실행 ... 그리고 결과를 생성

Row 1: 
    rdr["dbID"]: foo 
    rdr["dbName"]: fooDB 
    rdr["dbCreated"]: 2013-04-05 11:23:02 
Row 2: 
    rdr["dbID"]: bar 
    rdr["dbName"]: barDB 
    rdr["dbCreated"]: 2013-04-08 14:19:27 
Done. 
+0

감사합니다. 이것은 훨씬 빠릅니다. 5 초 이내에 큰 데이터베이스를 변환 할 수 있습니다! 유일한 문제는 진행률 표시 줄을 업데이트하려고하면 변환 중에 양식이 멈추는 것 같습니다. 일종의 비 (non-issue) 종류이지만, 실행이 진행 막대가 필요하기에 충분히 느리지 않기 때문에. 다시 한 번 감사드립니다! 최종 결과가 어떻게 표시되는지 질문을 업데이트합니다. –

2

당신은 당신은 배열이나 컬렉션의 데이터를 유지 한 후 데이터베이스에 액세스 더 나을 수 있습니다 중첩 루프 내부에서 (모든 행과 열)

using (OleDbCommand cmnd = new OleDbCommand(string.Format("SELECT {0} FROM {1} 

을 데이터베이스를 때리고있다.

+0

나는 이것에 대해 가지고 있지만, 그것이 그것이 글쓰기와 관련이 있다고 믿는다면 그것이 느려지는 부분을 고쳐 줄 것인지 확신 할 수 없다. 입력 해 주셔서 감사합니다. –

+0

** 업데이트 : ** 좋아요. 이제 주말 이후로 돌아 왔습니다. 코드의 작은 조정을 통해 읽기 및 쓰기를 분리하여 하나의 루프에있는 값으로 들쭉날쭉 한 배열을 채우고 다른 루프에 값을 씁니다. . 이것은 나의 이론이 잘못되었다는 것을 증명했으며, 사실 많은 시간을 필요로하는 독서입니다. 당신이 옳았. 루프 내부에서 데이터베이스를 치지 않고 배열을 채울 수있는 방법에 대한 아이디어가 있습니까? 네가 여기 뭔가있는 것 같아. –

+0

이 질문을 해결하면 올바른 답변을 표시해 주셔서 감사합니다. – Danahi

1

간단한 수학 계산이 이유를 알려줍니다. (데이터의 양)

27 * 12,256 = 330,912

27 * 500 = 13500

13,500분의 330,912 = 24,512

그래서 당신의 큰 문이 24512 배 더 크다!

(시간 현명) = 1800

5분의 1,800

30 * 60 = 360

그래서 시간이 360 배 더 크다!

코드가 좋지 않은 것처럼 보일 수 있습니다.

+1

코드가 일정한 페이스로 느리게 느껴지지 않습니까? 나는'OleDbDataReader'와'while (dataReader.read)'-loop을 사용하여 데이터베이스의 데이터 양에 따라 속도를 일정하게 유지하면서 실험을하고있었습니다. –

관련 문제