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 行,将所有记录从一个表移动到另一个表需要很长时间,特别是通过网络。有没有办法让它更快?

我一直在做一些阅读,并且有几个选项可以处理来自数据库的数据,例如数据适配器、读取器、集合和表。对于这种情况,哪个更快?我应该使用不同的方法吗?

4

2 回答 2

0

我看到的两件事是,首先您要为每个插入打开和关闭连接,这通常是您最昂贵的操作,因此您不会想要这样做。您也可以尝试对它们进行批处理,而不是一次执行它们。当你这样做时,你必须小心,因为事情可能会在大更新的过程中中断,所以你会想在事务中做事情。在不太了解您的数据结构的情况下,我重构了您的方法,一次批处理 100 个。首先创建一个名为 move items 的小助手方法,它接受一个连接和一个 id 列表。不要在此尝试捕获,稍后您会看到原因。

注意:此方法不使用参数,我强烈建议您更改它以执行此操作。

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

接下来,您将更改您的主要方法以打开数据库连接一次,然后一次调用此方法 100 个 id。此方法将有一个 try catch,因此如果对 MoveItems 的调用引发异常,它将在此 main 方法中被捕获。

// 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 次也应该会给你更好的性能。

于 2013-06-02T01:48:43.543 回答
-1

我可能是错的,但为了让它更快,你无能为力。毕竟,您想获取整个表数据并将其信息插入另一个表。如果您的桌子不小,该过程将需要一些时间。但是,您可以尝试使用下面的代码。它应该可以解决问题并节省一些时间。

INSERT INTO TABLE2 (FIELDNAME_IN_TABLE2, FIELDNAME2_IN_TABLE2)
SELECT FIELDNAME_IN_TABLE1, FIELDNAME2_IN_TABLE1
FROM TABLE1
于 2013-06-02T01:11:06.607 回答