使用Parallel复制表会导致MySQL死锁

时间:2014-01-25 00:59:16

标签: c# mysql multithreading parallel-processing deadlock

我正在创建一个程序,它将db1中所​​有表的数据组合到db2中的一个表中。但它会给出死锁错误。

这是我的代码。

Parallel.ForEach(tableList, table =>
{
    using (MySqlConnection conn = new MySqlConnection(DBconnection))
    {
        using (MySqlCommand cmd = new MySqlCommand(query, conn))
        {
            try
            {
                conn.Open();
                cmd.CommandText = "INSERT INTO db2.targetTable (id, value1, value2) " +
                "SELECT (SELECT id FROM db2.User u WHERE u.id = user LIMIT 1), " +
                "value1, value2 FROM db1." + table;
                cmd.CommandTimeout = 600000;
                cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
                Console.WriteLine("ERROR : " + ex.Message);
        }
    }
}

我认为子查询会导致问题。

也许如果我添加此代码,它可以解决问题:

  Object sync = new Object();
  lock (sync)
  {
     cmd.ExecuteNonQuery();
  }

但我觉得效率不高。这是正确的解决方案吗?或者有更好的解决方案,请给我一个示例代码。

1 个答案:

答案 0 :(得分:1)

目前尚不清楚是什么导致了僵局。 (请注意,涉及MyISAM表的SQL操作尝试获取整个表的独占锁,因此我假设您使用的是InnoDB或MyISAM以外的其他存储引擎。)

我会避免SELECT列表中的相关子查询,而是使用JOIN模式。我相信,通过SELECT列表中的子查询,MySQL将为外部查询中返回的每一行执行该子查询。

INSERT INTO db2.targetTable (id, value1, value2) 
SELECT u.id
     , t.value1
     , t.value2 
  FROM db1.table t
  LEFT
  JOIN db2.User u
    ON u.id = t.user

语句中的子查询包含LIMIT 1子句。如果需要,因为id表中的db2.User列不是唯一的(这可能很奇怪,但可能),那么我上面提到的查询需要包含GROUP BY <db1.table1 PRIMARY KEY>,避免从源行创建重复的行。

如果db1.table的PRIMARY KEY为id,那么:

INSERT INTO db2.targetTable (id, value1, value2) 
SELECT u.id
     , t.value1
     , t.value2 
  FROM db1.table t
  LEFT
  JOIN db2.User u
    ON u.id = t.user
 GROUP BY t.id