2013-02-06 48 views
0

我正在构建一个与Oracle 11g数据库交谈的.NET应用程序。我试图从第三方提供的Excel文件中提取数据并插入(UPDATE记录是否存在,INSERT如果不存在),但是在性能方面存在一些问题。来自外部数据源的Oracle MERGE

这些Excel文件将取代资费代码和说明,因此每个文件中有几千条记录。

| Tariff |  Description  | 
|----------------------------------------| 
| 1234567890 | 'Sample description here' | 

我做了批量插入一些研究,甚至还写道,在应用程序打开一个交易功能,执行一堆UPDATEINSERT语句,然后提交。不幸的是,这需要很长时间,并延长了应用程序和数据库之间的会话。

public void UpsertMultipleRecords(string[] updates, string[] inserts) { 
    OleDbConnection conn = new OleDbConnection("connection string here"); 
    conn.Open(); 
    OleDbTransaction trans = conn.BeginTransaction(); 
    try { 
     for (int i = 0; i < updates.Length; i++) { 
      OleDbCommand cmd = new OleDbCommand(updates[i], conn); 
      cmd.Transaction = trans; 
      int count = cmd.ExecuteNonQuery(); 
      if (count < 1) { 
       cmd = new OleDbCommand(inserts[i], conn); 
       cmd.Transaction = trans; 
      } 
     } 
     trans.Commit(); 
    } catch (OleDbException ex) { 
     trans.Rollback(); 
    } finally { 
     conn.Close(); 
    } 
} 

我发现通过向汤姆说做这样的事情的一种有效的方法是使用Oracle MERGE声明,在9i中实现的。据我所知,这只能使用Oracle中的两个现有表。我尝试过,但不了解临时表,或者如果这是可能的。如果我在MERGE上创建了一个只包含我的数据的新表,我仍需要一种可靠的批量插入方式。

回答

0

我通常上传我的文件以合并的方式是首先插入一个加载表与sql*loader,然后从加载表执行合并语句到目标表中。

临时表只会在会话期间保留它的内容。我期望sql * loader在完成时结束会话,所以最好使用在合并后截断的普通表。

merge into target_table t 
using load_table l on (t.key = l.key) -- brackets are mandatory 
when matched then update 
set t.col = l.col 
, t.col2 = l.col2 
, t.col3 = l.col3 
when not matched then insert 
(t.key, t.col, t.col2, t.col3) 
values 
(l.key, l.col, l.col2, l.col3) 
+0

一个问题:我将不得不从Web应用程序运行sql * loader以便重复使用它。这可能吗? – tedski

+0

它可以从命令行运行,但Web服务器也应该是我猜测的数据库服务器。不是一个好习惯。 可能更适合使用.NET批量插入。提示:如果在BEGIN ... END中有很多插入语句,正文中,Oracle会将其视为单个语句并仅解析一次。快得多。 – winkbrace

+0

不错的建议。我最终使用这篇文章进行批量插入:http://dotnetslackers.com/articles/ado_net/BulkOperationsUsingOracleDataProviderForNETODPNET.aspx 我创建了一个表来保存数据并使用了你的'MERGE'语句。它工作得很好。谢谢! – tedski