簡體   English   中英

為什么這段代碼會變慢?

[英]Why is this code slowing down?

我目前正在將許多Access數據庫轉換為Xml文件。 我之前已經做過,但仍然有上一個項目中的代碼。 但是,這段代碼不會讓我隨意構造xml,這是我這次需要做的。 我使用XDocumentfor -loops實現這一點,但一對夫婦的1000行數據后得到慢得令人難以置信。

讀完XDocument的工作原理后,我發現XElement.Add實際上復制了整個xml代碼並添加了new元素,因為它將所有內容都粘貼回了文件中。 如果這是真的,那可能就是問題所在。

這是從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秒鍾。

更新:好的,所以我現在周末結束后又回來了,我在代碼中做了一些小的調整,通過在一個循環中填充一個鋸齒狀數組並在另一個循環中寫入這些值,將讀取和寫入分開。 這證明了我的理論是錯誤的,實際上這需要花費很多時間。 關於如何用值填充數組而不在循環內訪問數據庫的任何想法?

UPDATE2:這是切換到DataReader.Read()循環並立即收集所有數據之后的最終結果。

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

請原諒我,但我認為您正在使您的生活變得比原本需要的更加復雜。 如果使用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.

您正在從嵌套循環(所有行和列)內部訪問數據庫

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

您最好將數據保留在數組或集合中,然后再訪問數據庫。

簡單的數學計算將告訴您原因。 (數據量)

27 * 12256 = 330912

27 * 500 = 13500

330912/13500 = 24512

因此,您的重要聲明要大24512倍!

(浪費時光)

30 * 60 = 1800

1800/5 = 360

因此您的時間是360倍!

您會看到您的代碼似乎並沒有做壞事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM