0

性能について質問です。これが私のシナリオです。

私はMYSQLデータベースと、クエリの基準に従って、あるテーブルから別のテーブルにレコードを時々移動するアプリケーションを持っています。これが行われる方法は次のとおりです。

foreach(object obj in list)
{
    string id = obj.ToString().Split(',')[0].Trim();
    string query = " insert into old_records select * from testes where id='" + 
                    id + "';" + " delete from testes where id='" + id +"'";

    DB _db = new DB();
    _db.DBConnect(query);

これは私がデータベースに接続する方法です:

DataTable _dt = new DataTable();
MySqlConnection _conn = new MySqlConnection(connectionString);
MySqlCommand _cmd = new MySqlCommand
{
    Connection = _conn,
    CommandText = query
};
MySqlDataAdapter _da = new MySqlDataAdapter(_cmd);
MySqlCommandBuilder _cb = new MySqlCommandBuilder(_da);

_dt.Clear();

try
{
    _conn.Open();
    _cmd.ExecuteNonQuery();
    _da.Fill(_dt);
}

catch (MySqlException ex)
{
    Console.WriteLine(ex.Message);
}

finally
{
    if (_conn != null) _conn.Close();
}
return _dt;

私の質問は、テーブルに 4000 行ほどあり、すべてのレコードを 1 つのテーブルから別のテーブルに、特にネットワークを介して移動するには多くの時間がかかるということです。これをより速くする方法はありますか?

私はいくつかの読書を行ってきましたが、データアダプター、リーダー、セット、テーブルなど、DB からのデータを処理するためのオプションがいくつかあります。この場合、どちらが速いですか?別の方法を使用する必要がありますか?

4

2 に答える 2

0

私が見る2つのことは、最初に各挿入の接続を開いたり閉じたりしていることです。これは通常、最も高価な操作であるため、やりたくないでしょう。一度に行うのではなく、バッチ処理を試すこともできます。これを行う場合、大規模な更新の途中で問題が発生する可能性があるため、注意する必要があるため、トランザクションで処理する必要があります。データ構造がどのように見えるかについてあまり知らずに、一度に 100 個のバッチ処理を行うようにメソッドをリファクタリングしました。最初に、接続と ID のリストを受け取る move items という小さなヘルパー メソッドを作成します。これで try catch を実行しないでください。理由は後でわかります。

注:このメソッドはパラメーターを使用しません。そのように変更することを強くお勧めします。

private static void MoveItems(MySqlConnection conn, List<string> moveList)
{
    string query = string.Format("insert into old_records select * from testes where id IN({0});" + " delete from testes where id IN({0})", string.Join(",", moveList.ToArray()));

    var cmd = new MySqlCommand
    {
        Connection = conn,
        CommandText = query
    };

    cmd.ExecuteNonQuery();
}

次に、データベース接続を 1 回開くようにメイン メソッドを変更し、一度に 100 個の ID に対してこのメ​​ソッドを呼び出します。このメソッドには try キャッチがあるため、MoveItems の呼び出しで例外がスローされた場合、このメイン メソッドでキャッチされます。

// the using statement will call your dispose method
using (var conn = new MySqlConnection(connectionString))
{
    // open the connection and start the transaction
    conn.Open();
    var transaction = conn.BeginTransaction();

    // createa  list to temporarily store the ids
    List<string> moves = new List<string>();

    try
    {
        // clean the list, do the trim and get everything that's not null or empty
        var cleanList = list.Select(obj => obj.ToString().Split(',')[0].Trim()).Where(s => !string.IsNullOrEmpty(s));

        // loop over the clean list
        foreach (string id in cleanList)
        {
            // add the id to the move list
            moves.Add("'" + id + "'");

            // batch 100 at a time
            if (moves.Count % 100 == 0)
            {
                // when I reach 100 execute them and clear the list out
                MoveItems(conn, moves);
                moves.Clear();
            }
        }

        // The list count might not be n (mod 100) therefore see if there's anything left
        if (moves.Count > 0)
        {
            MoveItems(conn, moves);
            moves.Clear();
        }

        // wohoo! commit the transaction
        transaction.Commit();
    }
    catch (MySqlException ex)
    {
        // oops!  something happened roll back everything
        transaction.Rollback();
        Console.WriteLine(ex.Message);
    }
    finally
    {
        conn.Close();
    }
}

その100の数字で遊ぶ必要があるかもしれません。MySQL を頻繁に使用していたとき、IN を実行することと Or ステートメントのリスト (Id = 'ID1' OR id = 'ID2' ...) を与えることの間にいくつかのパフォーマンスの違いを見たのを覚えています。しかし、40 個のステートメントまたは 80 個のステートメントを実行すると、パフォーマンスが確実に向上します。また、データベース接続を 4000 回開くのではなく 1 回開くと、パフォーマンスが大幅に向上します。

于 2013-06-02T01:48:43.543 に答える