2014-01-25 28 views
0

我正在制作一个程序,它将db1中所​​有表的数据结合到db2中的一个表中。但它会导致死锁错误。使用并行复制表导致MySQL死锁

这是我的代码。

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

但我认为它是没有效率。这是一个正确的解决方案?或者有更好的解决方案,请给我一个示例代码。

+0

你试图通过使用并行DML操作,以解决什么问题? – spencer7593

回答

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子句。如果这是必要的,因为db2.User表中的id列不是唯一的(这可能很奇怪,但可能),那么我上面给出的查询需要包括GROUP BY <db1.table1 PRIMARY KEY>,以避免从源行创建重复行。

如果db1.table有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 
+0

是的,我犯了错误的子查询部分。谢谢。 – KimchiMan