Oracle 通过存储过程进行批量插入。花费太多时间

Posted

技术标签:

【中文标题】Oracle 通过存储过程进行批量插入。花费太多时间【英文标题】:Oracle bulk insert via stored proc. taking too much time 【发布时间】:2012-02-13 11:33:49 【问题描述】:

我正在尝试有效地从 c# 代码到 oracle 数据库进行批量插入/更新。 如果我通过语句来完成,那么它不会花费太多时间。

我正在使用 ODP.NET 目前通过下面的存储过程插入 6000 条记录需要 15 分钟。 我必须使用这个存储过程,因为它会生成唯一的 user_id。

这个过程是在做自动提交吗?我应该关闭任何自动提交设置吗?

请提出有效的方法。

 CREATE OR REPLACE
PROCEDURE sbx_staging_insert_user(client       IN varchar2,
                    username     IN varchar2,
                    comm_type    IN varchar2,
                    email_addr   IN varchar2,
                    buddy_name   IN varchar2,
                    --default_flag IN char,
                    user_id      OUT INT)

AS
BEGIN
select sbx_staging_user_id_seq.nextval into user_id from dual;
insert into sbx_staging_user
  (user_id,
   client,
   username,
   comm_type,
   email_addr,
   buddy_name,
   default_flag)
values
  (user_id,
   client,
   username,
   comm_type,
   email_addr,
   buddy_name,
  'Y');
   end sbx_staging_insert_user;

而 C# 代码是:

  cmd.Transaction = conn.BeginTransaction();

                        cmd.CommandType = CommandType.Text;

                        cmd.CommandText = "sbx_staging_insert_user";
                        cmd.CommandType = CommandType.StoredProcedure;

                        var userClientParam = new OracleParameter(":client", OracleDbType.Varchar2);
                        var usernameParam = new OracleParameter(":username", OracleDbType.Varchar2);
                        var commTypeParam = new OracleParameter(":comm_type", OracleDbType.Varchar2);
                        var defaultParam = new OracleParameter(":default_flag", OracleDbType.Char)  Size = 1;
                        var emailParam = new OracleParameter(":email_addr", OracleDbType.Varchar2)  IsNullable = true ;
                        var buddyParam = new OracleParameter(":buddy_name", OracleDbType.Varchar2)  IsNullable = true ;
                        var userIdParam = new OracleParameter(":user_id", OracleDbType.Int32)  Direction = ParameterDirection.Output ;

                        cmd.Parameters.Add(userClientParam);
                        cmd.Parameters.Add(usernameParam);
                        cmd.Parameters.Add(commTypeParam);
                        //cmd.Parameters.Add(defaultParam);
                        cmd.Parameters.Add(emailParam);
                        cmd.Parameters.Add(buddyParam);
                        cmd.Parameters.Add(userIdParam);

                        var cuList = new List<string>(Users.Count);
                        var uList = new List<string>(Users.Count);
                        var ctList = new List<string>(Users.Count);
                        var dfList = new List<char>(Users.Count);
                        var eaList = new List<string>(Users.Count);
                        var bnList = new List<string>(Users.Count);
                        var uiList = new List<decimal>(Users.Count);

                        int loopCnt = 0;
                        foreach (var ud in Users)
                        
                            cuList.Add(ud.User.Client);
                            uList.Add(ud.User.Username);
                            ctList.Add(ud.User.CommType);
                            dfList.Add(ud.User.Default ? 'Y' : 'N');
                            eaList.Add(ud.User.Email);
                            bnList.Add(ud.User.BuddyName);

                            uiList.Add(-1);
                        

                        userClientParam.Value = cuList.ToArray();
                        usernameParam.Value = uList.ToArray();
                        commTypeParam.Value = ctList.ToArray();
                        //defaultParam.Value = dfList.ToArray();
                        emailParam.Value = eaList.ToArray();
                        buddyParam.Value = bnList.ToArray();
                        userIdParam.Value = uiList.ToArray();

                        cmd.ArrayBindCount = cuList.Count;//Users.Count;//
                        cmd.ExecuteNonQuery();
                        cmd.Transaction.Commit();

【问题讨论】:

为什么需要程序?为什么不:插入 my_table(id, ...) 值 (my_seq.nextval, ...); “用户”从何而来?它来自数据库中的表吗? @tbone - 看起来它需要一个 returning 子句来获取 ID,但仍然可以作为一个简单的 insert 而不是一个过程来做到这一点 @tbone 我需要在 c# 代码中返回 ID。我不知道除了存储过程之外的其他方式。你能回答如何只插入并取回ID。另外,为什么存储过程那么慢?甚至 Arraybinding 是一次发送所有数据(我希望)并在 DB 上调用 proc。 @MunishGoyal 您上面的 C# 代码不使用或不需要 nextval 值。您的 C# 代码只是调用该过程。如果你真的需要 nextval 值,请在插入中使用“returning into”子句。你不应该调用一个过程来做这个插入 【参考方案1】:

尝试这样的事情(未经测试,为简洁起见):

public void insertRows()

 if (Users.Count > 0)
 
  OracleTransaction trans=_conn.BeginTransaction();
  try
  
   // create insert statement with bind vars
   Stringbuilder sb = new Stringbuilder();
   sb.Append("INSERT into sbx_staging_user(");
   sb.Append("client,");
   sb.Append("username,");
   sb.Append("user_id");
   sb.Append(") VALUES (");
   sb.Append(":client,");
   sb.Append(":username,");
   sb.Append("seq_user_id.nextval");
   sb.Append(") ");

   OracleCommand cmd = new OracleCommand(sb.ToString(), _conn);

   string[] ary_client = new string[Users.Count];
   string[] ary_username = new string[Users.Count];

   for (int i=0; i<Users.Count; i++)
   
    User row=Users[i];
    ary_client[i]=row.client;
    ary_username[i]=row.username;
   
   // prepare bind vars(bind in bulk using arrays)
   OracleParameter prm=new OracleParameter();
   cmd.Parameters.Clear();
   cmd.ArrayBindCount=Users.Count;
   cmd.BindByName=true;

   prm=new OracleParameter("client", OracleDbType.Varchar2); prm.Value=ary_client; cmd.Parameters.Add(prm);
   prm=new OracleParameter("username", OracleDbType.Varchar2); prm.Value=ary_username; cmd.Parameters.Add(prm);

   cmd.ExecuteNonQuery();
   trans.Commit();
   trans.Dispose();
  
  catch 
   trans.Rollback();
   trans.Dispose();
   throw;
  
 

【讨论】:

【参考方案2】:

也许您应该将批量逻辑移至 plsql。 在此处查看示例:http://dotnetslackers.com/articles/ado_net/BulkOperationsUsingOracleDataProviderForNETODPNET.aspx

【讨论】:

以上是关于Oracle 通过存储过程进行批量插入。花费太多时间的主要内容,如果未能解决你的问题,请参考以下文章

mysql存储过程怎样批量插入数据

mysql存储过程实现数据查询与插入

oracle存储过程怎样批量插入新数据

oracle表批量插入数据

批量修改oracle数据库中的某一个字段?

requestLocationUpdates() 花费太多时间或根本不起作用