我有一个将数据插入Oracle数据库的c#过程。我试图使用批量插入,但性能非常糟糕,我不知道为什么。插入超过100'000行大约需要1小时30分!
这是我的插入程序:
internal void InsertPublications(DateTime aDate, List<Model.Publication> aPublications, Action<int> aProgress, Action<int> aCallBack)
{
List<List<Model.Publication>> _Publications = Split(aPublications, 128);
int _InsertedCount = 0;
var _Worker = new BackgroundWorker() { WorkerReportsProgress = true };
_Worker.DoWork += (_Sender, _Args) =>
{
var _TableName = string.Format("SRC_PUBLICATION_{0}", aDate.ToString("yyyyMMdd"));
OracleCommand _Command;
this.Connect();
try
{
this.CreateOrReplaceTable(_TableName, SQL_CREATE_PULICATIONS_TABLE);
foreach (var _PublicationSub in _Publications)
{
if (!DlgParamPublication.alive)
{
break;
}
_Command = this.Connection.CreateCommand();
_Command.CommandText = string.Format(SQL_INSERT_PULICATIONS, _TableName);
_Command.CommandType = CommandType.Text;
_Command.BindByName = true;
_Command.ArrayBindCount = _PublicationSub.Count;
_Command.Parameters.Add(":ANNEE", OracleDbType.NVarchar2, _PublicationSub.Select(_Item => _Item.Year).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_PUBLICATION", OracleDbType.NVarchar2, _PublicationSub.Select(_Item => _Item.Pid).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_TYPE_PUBLICATION", OracleDbType.NVarchar2, _PublicationSub.Select(_Item => _Item.IdePublicationType.ToString().ToLower()).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_TYPE_TRAVAIL", OracleDbType.NVarchar2, _PublicationSub.Select(_Item => _Item.IdeTypeOfWork.ToString().ToLower()).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_NIVEAU_ELEMENT_ORG", OracleDbType.NVarchar2, _PublicationSub.Select(_Item => _Item.UserRefType.ToString().ToLower()).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_ELEMENT_ORG", OracleDbType.NVarchar2, _PublicationSub.Select(_Item => _Item.UserRefValue).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":AUTEUR", OracleDbType.NClob, _PublicationSub.Select(_Item => _Item.Author).ToArray(), ParameterDirection.Input);
_InsertedCount += _Command.ExecuteNonQuery();
_Worker.ReportProgress(0, _InsertedCount);
}
catch (Exception _Exc)
{
ViewModel.DlgParamPublication.Logger.LogException("INSERT PUBLICATIONS", _Exc, false);
}
finally
{
this.Disconnect();
}
};
_Worker.ProgressChanged += (_Sender, _Args) => { aProgress((int)_Args.UserState); };
_Worker.RunWorkerCompleted += (_Sender, _Args) => { aCallBack(_InsertedCount); };
// Start background thread
if (DlgParamPublication.alive)
{
_Worker.RunWorkerAsync();
}
}
知道为什么花了这么长时间?
有没有人有其他建议?我无法解决问题。
答案 0 :(得分:1)
这个想法是在单个存储的proc调用中为每个参数发送值数组。您实际上是在发送一个单值 n 的数组,其中 n 是_Publications
的长度。
移除外圈并将_PublicationSub.Select
替换为_Publications.Select
。
您还需要更改绑定计数_Command.ArrayBindCount = _Publications.Count;
为了更容易,我认为这将起作用:
try
{
this.CreateOrReplaceTable(_TableName, SQL_CREATE_PULICATIONS_TABLE);
if (!DlgParamPublication.alive)
{
break;
}
_Command = this.Connection.CreateCommand();
_Command.CommandText = string.Format(SQL_INSERT_PULICATIONS, _TableName);
_Command.CommandType = CommandType.Text;
_Command.BindByName = true;
_Command.ArrayBindCount = _Publications.Count;
_Command.Parameters.Add(":ANNEE", OracleDbType.NVarchar2, _Publications.Select(_Item => _Item.Year).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_PUBLICATION", OracleDbType.NVarchar2, _Publications.Select(_Item => _Item.Pid).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_TYPE_PUBLICATION", OracleDbType.NVarchar2, _Publications.Select(_Item => _Item.IdePublicationType.ToString().ToLower()).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_TYPE_TRAVAIL", OracleDbType.NVarchar2, _Publications.Select(_Item => _Item.IdeTypeOfWork.ToString().ToLower()).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_NIVEAU_ELEMENT_ORG", OracleDbType.NVarchar2, _Publications.Select(_Item => _Item.UserRefType.ToString().ToLower()).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":IDE_ELEMENT_ORG", OracleDbType.NVarchar2, _Publications.Select(_Item => _Item.UserRefValue).ToArray(), ParameterDirection.Input);
_Command.Parameters.Add(":AUTEUR", OracleDbType.NClob, _Publications.Select(_Item => _Item.Author).ToArray(), ParameterDirection.Input);
_InsertedCount += _Command.ExecuteNonQuery();
_Worker.ReportProgress(0, _InsertedCount);
}
catch (Exception _Exc)
{
ViewModel.DlgParamPublication.Logger.LogException("INSERT PUBLICATIONS", _Exc, false);
}
finally
{
this.Disconnect();
}
您可能希望删除后台工作人员的进度,因为这是单次通话中的一次性0-100%交易。
答案 1 :(得分:1)
我将尝试在foreach循环之外创建OracleCommand和所有OracleParameter 在循环内部,我将添加当前迭代的值
_Command = this.Connection.CreateCommand();
_Command.CommandText = string.Format(SQL_INSERT_PULICATIONS, _TableName); _Command.CommandType = CommandType.Text;
_Command.BindByName = true;
_Command.Parameters.Add(":ANNEE", OracleDbType.NVarchar2, "", ParameterDirection.Input); _Command.Parameters.Add(":IDE_PUBLICATION", OracleDbType.NVarchar2, "", ParameterDirection.Input);
.....
foreach (var _PublicationSub in _Publications)
{
_Command.Parameters[":ANNEE"].Value = _PublicationSub.Select(_Item => _Item.Year).ToArray();
....
}
答案 2 :(得分:1)
我不确定,但问题可能是BindByName。我建议使用this example中的数字绑定。