2

Oracleデータベースにデータを挿入するac#プロシージャがあります。バルクインサートを使ってみましたが、性能がひどく悪く、理由がわかりません。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();
    }
}

なぜそんなに時間がかかるのか分かりますか?

アップデート

誰か別の提案がありますか?問題を解決できませんでした。

4

3 に答える 3

1

よくわかりませんが、BindByNameに問題がある可能性があります。この例のように数値バインディングをお勧めします 。

于 2013-01-26T04:20:33.840 に答える
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();
     ....
}
于 2012-04-23T12:05:06.250 に答える
1

アイデアは、単一のストアド プロシージャ呼び出しで各パラメーターの値の配列を送信することです。単一の値の配列を効果的に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();
    }

これは 1 回の呼び出しで 0 ~ 100% のワンショット取引であるため、バックグラウンド ワーカーの進行状況を削除することをお勧めします。

于 2012-04-23T11:58:25.303 に答える