4

現在、多数の Access データベースを Xml ファイルに変換中です。以前にこれを行ったことがありますが、以前のプロジェクトのコードがまだ残っています。ただし、このコードでは、XML を思い通りに構成できません。これは、今回行う必要があることです。XDocumentこれを実現するために with for-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 データベースの変換には 1 秒しかかかりません。これら2つをマージする方法はありますか?

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 秒かかります。

更新:わかりましたので、週末の後に戻ってきました。コードを少し調整して、1 つのループでギザギザの配列に値を入力し、別のループで値を書き込むことで、読み取りと書き込みを分離しました。これは私の理論が間違っていることを証明しており、実際には非常に時間がかかるのは読書です. ループ内でデータベースにアクセスせずに配列に値を入力する方法についてのアイデアはありますか?

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

3 に答える 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.
于 2013-04-08T18:38:18.410 に答える
1

簡単な計算でその理由がわかります。(データ量)

27 * 12256 = 330912

27 * 500 = 13500

330912 / 13500 = 24512

したがって、あなたの大きな声明は24512倍大きくなります!

(時間的に)

30*60 = 1800

1800 / 5 = 360

あなたの時間は360倍大きくなります!

コードが悪いことをしているようには見えないことがわかります。

于 2013-04-05T08:24:51.270 に答える