2016-04-25 41 views
2

我有,我必须一般来说检查整个基地做东西控制台应用程序...倍数连接到Oracle - 多任务

要做到这一点,我使用Tasks这样的:

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()); 

所以基本上我想要运行10天一次在if (taskList.Count >= 2 * 5)你可能注意到了,但问题是,我FooBoo方法有多个连接到一个Oracle数据库。

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(); 
      } 
     } 
    } 

的问题是:对于每一个“天”,它tooks约2小时来处理一切......我们有一个计划,每天备份我们的数据库造成该数据库停止大约10分钟...所以它会导致我的过程中锁...

那么我该怎么做?我手动停止这个过程,并再次启动它,避免已经执行的日期。但是如果我打开了20个连接,他们会保持这种方式......所以我必须每次都杀掉这些会话......有没有办法强制所有连接处置?

编辑:

MyTable有50英里行....由ID | STATE | DATE组成......基本上我必须要跨越这些国家与他们的日期...... 因此,最大的延迟它的数据库。 ..它还挺一个已知的问题,我们要重构整个数据库模型....我们要尽快做到这一点...

但不管怎么说,尽管处理时间,如果我可以管理(或强制)连接杀死,它会很好...

任何想法?

+0

'每天两小时'处理时间的大部分发生在哪里?它在数据库端还是应用端?如果你用更小的批次更频繁地运行它,这可能会更好吗?这可能不是一个简单修复的情况;在分析整个过程之后可能需要重新设计。 – gmiley

+0

“日”合并过程不应该花费2个小时左右的时间来运行;即使在数百万行的数据库表上,它也应该在几分钟或更短的时间内运行。你能给我们一个粗略的想法:表'MyTable'中有多少行,'another_table'中有多少行 - 并且你的设计被设置为手动关闭和重启进程也是令人担忧的。另外,您的数据库应该使用适当的RMAN备份进入归档日志模式,因此您不必每天都进行数据库导出。 –

+0

大部分是在数据库端,当然..有一个相同的实现(没有任务),每天花费4个小时..而我设法在2个小时内完成......但我真的需要一些东西来控制所有连接....我用一些信息编辑了这个问题....“MyTable”和“another_table”每行有超过50英里的行......所以它很大。我必须将每条记录与其他大表连接起来......有时,连接会发生VARCHAR2(15)值...所以它的模型非常糟糕...... –

回答

1

好的,为了杀死一个会话,你需要一个DBA,如果你每周做几次,就不会有好的友谊!正如我和其他人指出的那样,不需要为备份而关闭数据库(除了冷备份)或甚至导出数据库,但是如果您有这些较长的合并过程,则一致的导出过程需要很长时间。因此,第一步是教育(很好)DBA如何使数据库处于归档日志模式,并让RMAN管理联机备份。

其次,你需要提高合并条件,以便合并列索引。它很可能是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,我会回答这个问题,而不是提供我的解决方案。 :)

您可以创建一个profile被然后分配给user到会话限制在一个特定的CONNECT_TIMEIDLE_TIME或两者兼而有之。然后,如果用户如果用户超过了CONNECT_TIME或IDLE_TIME会话资源 极限超过时间,根据http://docs.oracle.com/database/121/SQLRF/statements_6012.htm#SQLRF01310

,则数据库回滚当前事务并结束 该会话。当下一个用户进程发出呼叫时,数据库 将返回一个错误。

所以,你可以这样做:

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

然后在创建会话时,如果会话闲置5分钟后,甲骨文将杀死会话,如果它是24小时运行实,(24小时内在命令之间运行少于5分钟的命令)Oracle将终止会话。

+0

嘿人感谢回答!但是这些表格已经被编入索引...我并没有试图提高性能(即使这解决了问题)...我试图强制连接被杀...这是主要问题:( –

+0

更新我的答案来回答你的问题!建议使用资源管理而不是配置文件,但它比较复杂,但如果您有兴趣,请参阅以下参考资料:http://docs.oracle.com/database/121/ADMIN/dbrm.htm#CHDDCGGG –