2014-07-03 45 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方法...

相關問題