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 通过存储过程进行批量插入。花费太多时间的主要内容,如果未能解决你的问题,请参考以下文章