Multiples与Oracle的连接 - 多任务

时间:2016-04-25 15:04:29

标签: c# multithreading 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());

所以基本上我想在if (taskList.Count >= 2 * 5)注意到你一次 10天,但问题是我的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();
            }
        }
    }

问题是:对于每个“日”,它需要大约2个小时来处理所有内容......我们每天都有计划备份我们的数据库,导致数据库停止大约10分钟......所以它会导致锁定在我的过程中...

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

修改

MyTable有50英里的行....由ID | STATE | DATE组成...基本上我必须用他们的日期跨越那些状态...... 所以它在数据库上有很大的延迟...这是一个已知的问题,我们必须重构整个数据库模型....我们很快就会这样做......

但无论如何,尽管有处理时间,但如果我可以管理(或强制)连接终止,那就没关系......

有什么想法吗?

1 个答案:

答案 0 :(得分: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) 

您应该检查id上的fieldanother_table是否被编入索引,并在dateHappen上创建基于函数的索引:

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

对于数据库调优,只需在SQL工具中调用merge语句即可尝试不同的方法;然后你不必担心中途杀死合并,这会导致数据库回滚交易等方面的大量工作。

更新

好的,我会回答这个问题,而不是提供我的解决方案。 :)

您可以创建profile,然后将其分配给user,以限制与特定CONNECT_TIMEIDLE_TIME或两者的会话。然后,如果用户超过时间,则根据http://docs.oracle.com/database/121/SQLRF/statements_6012.htm#SQLRF01310

  

如果用户超过CONNECT_TIME或IDLE_TIME会话资源   限制,然后数据库回滚当前事务并结束   会议。当用户进程下一次发出调用时,数据库   返回错误。

所以你可以这样做:

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

然后在创建会话时,如果会话空闲5分钟,Oracle将终止会话,如果它运行稳定24小时,(运行24小时命令之间的命令少于5分钟)Oracle将杀死会议。