2014-07-03 31 views
0

我在网上搜索了一些东西,但没有什么帮助。我想用文章列表更新数据库,但我发现的方式非常慢。在mdb数据库中更新超过50,000行的最快方法c#

这是我的代码:

List<Article> costs = GetIdCosts(); //here there are 70.000 articles 
conn = new OleDbConnection(string.Format(MDB_CONNECTION_STRING, PATH, PSW)); 
conn.Open(); 
transaction = conn.BeginTransaction(); 

using (var cmd = conn.CreateCommand()) 
{ 
    cmd.Transaction = transaction; 

    cmd.CommandText = "UPDATE TABLE_RO SET TABLE_RO.COST = ? WHERE TABLE_RO.ID = ?;"; 

    for (int i = 0; i < costs.Count; i++) 
    { 
     double cost = costs[i].Cost; 
     int id = costs[i].Id; 

     cmd.Parameters.AddWithValue("data", cost); 
     cmd.Parameters.AddWithValue("id", id); 

     if (cmd.ExecuteNonQuery() != 1) throw new Exception(); 
    } 
} 

transaction.Commit(); 

但这种方式需要大量的分像10分钟以上。还有另一种方法来加速此更新?谢谢。

+0

您打算尝试去讨论该表上的约束条件,但是由于新数据的原因,当您再次激活时可能无法验证约束条件。 –

+1

在进入for循环之前,尝试用'cmd.Parameters.Add()'创建参数,然后执行'cmd.Prepare()'。然后,在循环中只分配参数值和'.ExecuteNonQuery()'。这可能会加快一点。 –

回答

2

尝试修改您的代码如下:

List<Article> costs = GetIdCosts(); //here there are 70.000 articles 

// Setup and open the database connection 
conn = new OleDbConnection(string.Format(MDB_CONNECTION_STRING, PATH, PSW)); 
conn.Open(); 

// Setup a command 
OleDbCommand cmd = new OleDbCommand(); 
cmd.Connection = conn; 
cmd.CommandText = "UPDATE TABLE_RO SET TABLE_RO.COST = ? WHERE TABLE_RO.ID = ?;"; 

// Setup the paramaters and prepare the command to be executed 
cmd.Parameters.Add("?", OleDbType.Currency, 255); 
cmd.Parameters.Add("?", OleDbType.Integer, 8); // Assuming you ID is never longer than 8 digits 

cmd.Prepare(); 
OleDbTransaction transaction = conn.BeginTransaction(); 
cmd.Transaction = transaction; 

// Start the loop  
for (int i = 0; i < costs.Count; i++) 
{ 
    cmd.Parameters[0].Value = costs[i].Cost; 
    cmd.Parameters[1].Value = costs[i].Id; 

    try 
    { 
     cmd.ExecuteNonQuery(); 
    } 
    catch (Exception ex) 
    { 
     // handle any exception here 
    } 
} 

transaction.Commit(); 
conn.Close(); 

cmd.Prepare方法将加快速度,因为它创建命令的数据源的编译版本。

+0

John我认为这是一个很好的解决方案,但在更新2篇文章后,在ExecuteNonQuery()上返回一个错误。错误是类型system.exception **的异常** – puti26

+0

我会更新我的答案,这是溜走了。 –

+0

'if(cmd.ExecuteNonQuery()!= 1)'引发异常被抛出。 ExecuteNonQuery返回受影响的行数。如果像我这样修改循环内的代码,它应该可以工作。 –

1

小的变化选项:

使用的StringBuilder和的String.format构建一个大的命令文本。

var sb = new StringBuilder(); 

for(....){ 
    sb.AppendLine(string.Format("UPDATE TABLE_RO SET TABLE_RO.COST = '{0}' WHERE TABLE_RO.ID = '{1}';",cost, id)); 
} 

更快速的选项:

如在第一个例子中构造一个SQL但这次使它看起来(在结果),如:

-- declaring table variable 
declare table @data (id int primary key, cost decimal(10,8)) 

-- insert union selected variables into the table 
insert into @data 
     select 1121 as id, 10.23 as cost 
union select 1122 as id, 58.43 as cost 
union select ... 


-- update TABLE_RO using update join syntax where inner join data 
-- and copy value from column in @data to column in TABLE_RO 
update dest 
set dest.cost = source.cost 
from TABLE_RO dest 
inner join @data source on dest.id = source.id 

这是最快的,你可以得到,而无需使用批量插入。

+0

我刚刚发现它可能不是T-SQL。对于Oracle更新加入,我发现这篇文章: http://stackoverflow.com/questions/2446764/oracle-update-statement-with-inner-join 然而,编程方法仍然是相同的。 – doker

+0

第一种方法我应该使用for循环中的executeNonQuery,并且cmd.CommandText = sb.ToString();对? – puti26

+0

右和右。 – doker

0

使用Ado.net和OleDb执行批量更新非常缓慢。如果可能,您可以考虑通过DAO执行更新。只需添加参考DAO库(COM-对象),并使用类似下面的代码(注意 - >未经):

// Import Reference to "Microsoft DAO 3.6 Object Library" (COM) 

string TargetDBPath = "insert Path to .mdb file here"; 

DAO.DBEngine dbEngine = new DAO.DBEngine(); 
DAO.Database daodb = dbEngine.OpenDatabase(TargetDBPath, false, false, "MS Access;pwd="+"insert your db password here (if you have any)"); 

DAO.Recordset rs = daodb.OpenRecordset("insert target Table name here", DAO.RecordsetTypeEnum.dbOpenDynaset); 

if (rs.RecordCount > 0) 
{ 
    rs.MoveFirst(); 

    while (!rs.EOF) 
    { 
     // Load id of row 
     int rowid = rs.Fields["Id"].Value; 

     // Iterate List to find entry with matching ID 
     for (int i = 0; i < costs.Count; i++) 
     { 
      double cost = costs[i].Cost; 
      int id = costs[i].Id; 

      if (rowid == id) 
      { 
       // Save changed values 
       rs.Edit(); 
       rs.Fields["Id"].Value = cost; 
       rs.Update(); 
      } 
     } 

     rs.MoveNext(); 
    } 
} 
rs.Close(); 

注意的事实是,我们正在做一个全表扫描这里。但是,除非表中的记录总数比更新记录的数量多很多个数量级,否则它应该仍然明显优于Ado.net方法...

相关问题