2016-04-25 8 views
2

私は一般詰め込むを行うためのベース全体をチェックしを話す必要がありますコンソールアプリケーションを持っている...倍数接続 - マルチタスク

これを行うには、私はこのようなTasks使用しています:

をだから、基本的に私はあなたが if (taskList.Count >= 2 * 5)に気づいたかもしれませんが、問題は私の FooBoo方法が持っているということであるよう 10日一度を実行したい
static void Main(string[] args) 
{ 
     var dateStart = DateTime.Now.AddDays(-35); 
     var dateEnd = DateTime.Now; 

     var taskList = new List<Task>(); 

     while (dateStart > dateEnd ? dateStart >= dateEnd : dateStart <= dateEnd) 
     { 
      var d = dateStart.Date; 
      var dispositivesBll = new DispositivesBll(); 
      taskList.Add(Task.Run(() => 
             { 
              dispositivesBll.Foo(d); 
             }).ContinueWith(
              x => dispositivesBll.Dispose()) 
           .ContinueWith(x => GC.Collect())); 

      var dispositivesBllNew = new DispositivesBll(); 
      taskList.Add(Task.Run(() => 
             { 
              dispositivesBllNew.Boo(d); 
             }).ContinueWith(
              x => 
              dispositivesBllNew.Dispose()) 
           .ContinueWith(x => GC.Collect())); 

      if (taskList.Count >= 2 * 5) 
      { 
       Task.WaitAll(taskList.ToArray()); 
       taskList.Clear(); 
      } 
      dateStart = dateStart > dateEnd ? dateStart.AddDays(-1) : dateStart.AddDays(1); 
     } 
     Task.WaitAll(taskList.ToArray()); 

1つのOracle Databaseへの複数接続。

public class DispositivesBll : IDisposable 
{ 
    private readonly OracleDal _oracleDal = new OracleDal(); 

    public void Foo(DateTime data) 
    { 

     var t1 = Task.Run(() => 
        { 
         _listSuccess = _oracleDal.GetSuccessList(); 
        }); 

     var t2 = 
      Task.Run(() => 
         { 
          listFailure = _oracleDal.GetFailureList(); 
         }); 

     t1.Wait(); 
     t2.Wait(); 

     foreach (var success in _listSuccess) 
     { 
      //Some logic to insert objects into a "mergeList" 
     } 

     if (mergeList.Any()) 
      Task.Run(() => _oracleDal.MergeList(mergeList)).Wait(); 
    } 

    public void Dispose() 
    { 
     if (_hash != null) 
      _hash.Clear(); 
     _hash = null; 

    } 
} 

と私のマージ方法:

public void MergeList(List<MyObject> mergeList) 
    { 
     using (var conn = new OracleConnection(Connection.ConnectionString)) 
     { 
      if (conn.State != ConnectionState.Open) 
       conn.Open(); 
      using (var oCommand = conn.CreateCommand()) 
      { 
       oCommand.CommandType = CommandType.Text; 
       oCommand.CommandText = string.Format(@" 
       MERGE INTO MyTable dgn 
       USING (select id from another_table where field = :xpe) d ON (TO_CHAR(dateHappen, 'DDMMYYYY') = {0} and id = :xId) WHEN MATCHED THEN 
        UPDATE SET OK = :xOk, dateHappen = SYSDATE 
       WHEN NOT MATCHED THEN 
        INSERT (fields....) 
        VALUES (values...)"); 
       oCommand.BindByName = true; 
       oCommand.ArrayBindCount = mergeList.Count; 



       oCommand.Parameters.Add(":xId", OracleDbType.Int32, 
             mergeList.Select(c => Convert.ToInt32(c.Id)).ToArray(), ParameterDirection.Input); 

       oCommand.Parameters.Add(":xPe", OracleDbType.Varchar2, 
             mergeList.Select(c => Convert.ToString(c.Xpe)).ToArray(), ParameterDirection.Input); 


       oCommand.ExecuteNonQuery(); 
      } 
     } 
    } 

問題がある:各「日」のために、それはすべてのものを処理するために約2時間をtooks ...そして、我々はバックアップに毎日の計画を持っている私達のデータベース原因データベースは約10分停止します...それは私のプロセスでロックを引き起こすでしょう...

私は何をしますか?私はこのプロセスを手動で停止し、既に実行された日付を避けて再度起動します。しかし、私は20の接続を開いている場合、彼らはそのように滞在していたので...私は毎回それらのセッションを殺す必要があります...すべての接続を処分するよう強制する方法はありますか?だから、

MyTableID | STATE | DATEによって構成さ50マイルの行が.... ...基本的に私は彼らの日程でそれらの状態を横断する必要がありました... それはデータベース上にある大きな遅延:

EDIT。 ..データベース全体のモデルをリファクタリングする必要があることはちょっと知られている問題です... ...

とにかく、処理時間にもかかわらず、力)接続を殺す、それは正常だろう...

アイデアは?

+0

「1日2時間」の処理時間の大半はどこにありますか?それはデータベース側かアプリケーション側か?小規模なバッチで頻繁に実行した方が良いかもしれませんか?これは簡単な修正がある場合ではないかもしれません。プロセス全体の分析後に再設計が必要になる可能性があります。 – gmiley

+0

「1日」のマージ処理は、実行に2時間近くかかることはありません。何百万行ものデータベース表であっても数分以内に実行する必要があります。 'MyTable'テーブルの行数と' another_table'の行数を大まかに知ることができます。また、手動でプロセスを強制終了して再起動するように設計されていることも気になります。また、適切なRMANバックアップを使用して、データベースをアーカイブ・ログ・モードにして、データベースのエクスポートを毎日行う必要はありません。 –

+0

大多数はデータベース側にあります。1日4時間かかる同じ実装(タスクなし)がありますが、2時間でやり遂げましたが、実際にはすべての接続を制御する必要があります....私はいくつかの情報で質問を編集しました.... 'MyTable'と' another_table'は50マイル以上の行を持っています。そして、私は他の大きなテーブルと各レコードを結合する必要があります...時々、VARCHAR2(15)の値との結合が発生します....その非常に悪いモデル... –

答えて

1

さて、セッションを終了するには、DBAを参加させる必要があります.1週間に数回すると、良い友情にはならないでしょう!自分自身や他の人が指摘しているように、データベースはバックアップのために(コールド・バックアップを除いて)、またはエクスポートのために停止する必要はありませんが、長い結合プロセスがあれば、一貫性のあるエクスポートにはかなりの時間がかかります。まず、データベースをアーカイブ・ログ・モードで教育し、RMANでオンライン・バックアップを管理するようにします。

第2に、マージ基準を改善して、マージする列のインデックスを作成する必要があります。 dateHappenが索引付けされている可能性がありますが、マージ基準内で関数を呼び出すので、ファンクション索引が作成されないかぎり、その索引は使用できません。私は、

TO_CHAR(dateHappen, 'DDMMYYYY') = {0} 

を特に指しています。そして一般的には、

USING (select id from another_table where field = :xpe) d 
ON (TO_CHAR(dateHappen, 'DDMMYYYY') = {0} and id = :xId) 

あなたはanother_tableidfieldがインデックス化されているかどうかを確認する必要があり、かつdateHappenにファンクション索引を作成:データベースのチューニングについて

create index i_date_string on whatever_table (TO_CHAR(dateHappen, 'DDMMYYYY')) 

を、単に呼び出しますSQLツールで文をマージして別のアプローチを試みる。そして、あなたが殺害について心配する必要はありませんと、トランザクションのロールバック、データベースに多くの作業を引き起こしてしまうwhicn途中、などをマージし

更新:

OK、私の代わりに質問にお答えします私のソリューションを提供しています。 :)

その後、特定のCONNECT_TIMEまたはIDLE_TIMEまたは両方へのセッションを制限するuserに割り当てられているprofileを作成することができます。ユーザが時間を超えた場合、ユーザはCONNECT_TIME又はIDLE_TIMEセッションリソース 制限を超える場合、http://docs.oracle.com/database/121/SQLRF/statements_6012.htm#SQLRF01310

によれば、データベースは、現在のトランザクションをロールバックし セッションを終了します。次にユーザプロセスがコールを発行すると、データベース がエラーを返します。それは24時間固体実行されている場合は、あなたのセッションが作成されたときに、セッションが5分間アイドル状態である場合

create profile MERGE_PROF limit idle_time 5 connect_time 86400; 
alter user BATCH_MERGER_USER profile MERGE_PROF; 

はその後、Oracleはセッションを殺す、と:

だから、これを行うことができます、(コマンド間で5分未満のコマンドを24時間実行すると)Oracleはセッションを終了します。

+0

回答!しかし、それらのテーブルはすでにインデックスされています...私は接続を強制終了しようとしています...それは主要な問題です:( –

+0

あなたの質問に答えて私の答えを更新しました!Oracleプロファイルの代わりにリソース管理を使用することをお勧めしますが、それはより複雑ですが、興味がある場合に備えて参照してください:http://docs.oracle.com/database/121/ADMIN/dbrm.htm#CHDDCGGG –