2013-04-05 78 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); 
    } 
} 

這是我的舊轉換器的代碼。這段代碼幾乎不受數據庫大小的影響,12 556數據庫只需要一秒鐘的時間進行轉換。那麼可能有合併這兩者的方法嗎?

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:好了,所以我特地在週末回來後,現在我在代碼中做了一個小的調整,以單獨的閱讀和寫作的填充值的鋸齒形陣列中的一個循環,並以書面形式另一個。這已經證明我的理論是錯誤的,事實上,閱讀需要很長時間。有關如何用數值填充數組而不碰循環內數據庫的想法?

UPDATE2:這是在切換到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 2013-04-05 08:16:09

+0

@ChrisBint不,我沒有。我可以在沒有任何第三方工具或軟件的情況下做這些嗎? – 2013-04-05 08:45:14

回答

3

原諒我,但我認爲你讓你的生活比需要的更復雜。如果您使用的是對象,則可以將其打開並逐行讀取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秒內轉換大數據庫!唯一的問題似乎是,如果我嘗試更新進度條,表單會凍結。雖然這是一個非問題,但由於執行速度不夠慢,導致進度條不必要。再次感謝! 我將更新問題以顯示最終結果的樣子。 – 2013-04-09 09:02:55

2

您從嵌套的循環內進入數據庫(所有的行和列)

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

你可能會更好將數據保持在一個數組或集合,然後訪問數據庫。

+0

雖然我對此有所瞭解,但我不確定這是否會解決放緩的部分,因爲我相信這與寫作而不是閱讀有關。儘管如此,儘管如此,感謝您的輸入! – 2013-04-05 08:48:41

+0

**更新:**好吧,所以我現在週末回來了,我在代碼中進行了一些小調整,以便通過在一個循環中填入一個鋸齒形數組並將值寫入另一個循環中來分隔讀取和寫入。這已經證明我的理論是錯誤的,事實上,閱讀需要很長時間。你是對的。你有沒有關於如何填充數組而不敲打循環內數據庫的想法?我想你在這裏做些什麼。 – 2013-04-08 06:44:21

+0

如果這個問題已經解決了,你可以標記正確的答案,謝謝。 – Danahi 2013-04-09 06:34:50

1

簡單的數學計算會告訴你爲什麼。 (數據量)

27 * 12256 = 330912

27 * 500 = 13500

一萬三千五百分之三十三萬零九百十二= 24512

所以你的大語句是大24512倍!

(時間方式)

30 * 60 = 1800

1800/5 = 360

所以你的時間是大360倍!

你可以看到你的代碼似乎沒有做壞事。

+1

這不會導致代碼以不變的速度變慢嗎?我正在嘗試使用帶有while(dataReader.read)'-loop的'OleDbDataReader',它的速度取決於數據庫中的數據量,速度不變。 – 2013-04-05 08:43:29