简体   繁体   English

与 Oracle 的多个连接 - 多任务

[英]Multiples Connections to Oracle - Multi Task

I have a console application that I must generally speaking check the entire base to do stuffs ...我有一个控制台应用程序,我必须一般来说检查整个基地做的东西...

To do so, I am using Tasks like this:为此,我正在使用这样的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());

So Basically I want to run 10 days at once as you may noticed at if (taskList.Count >= 2 * 5) but the problem is that my Foo and Boo methods have multiples connection to one Oracle Database.所以基本上我想一次运行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;

    }
}

and my Merge Method:和我的合并方法:

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

The problem is: For each "day" it tooks about 2 hours to process everything... and we have a daily plan to backup our database causing the database to stop about 10 minutes... so it would cause a lock in my process...问题是:对于每个“一天”,处理所有内容大约需要 2 个小时……我们有一个每日计划来备份我们的数据库,导致数据库停止大约 10 分钟……所以它会导致我的进程锁定...

So what I do?那我怎么办? I stop manually this process and start it again avoiding the dates already executed.我手动停止此过程并再次启动它以避免已执行的日期。 BUT if I have 20 connections opened, they would stayed that way... So I have to kill those sessions everytime... Is there a way to force all connections to dispose?但是,如果我打开了 20 个连接,它们会保持这种状态......所以我每次都必须终止这些会话......有没有办法强制处理所有连接?

EDIT:编辑:

MyTable has 50 mi rows.... composed by ID | STATE | DATE MyTable有 50 mi 行.... 由ID | STATE | DATE组成ID | STATE | DATE ID | STATE | DATE ... basically I have to cross those STATES with their DATES... So the big delay it's on the database... It's kinda a known issue that we have to refactor the entire database model.... and we are going to do it soon... ID | STATE | DATE ...基本上我必须将这些 STATES 与它们的 DATES 交叉......所以它在数据库上的大延迟......这是我们必须重构整个数据库模型的一个已知问题......我们正在尽快做...

But anyways, despite the process time, if I can just manage (or force) the connection kill, it would be fine...但无论如何,尽管有处理时间,如果我可以管理(或强制)连接终止,那就没问题了......

Any ideas?有任何想法吗?

Okay, in order kill a session, you would need to involve a DBA, which if you do several times a week, would not make for a good friendship!好的,为了终止会话,您需要让 DBA 参与进来,如果您每周这样做几次,就不会建立良好的友谊! As myself and others pointed out, a database should not need to be brought down for a backup (except for a cold backup), or for even a export, but if you have these long merge processes a consistent export would take quite a while.正如我和其他人指出的那样,数据库不应该被关闭以进行备份(冷备份除外),甚至是导出,但如果您有这些长合并过程,一致的导出将需要相当长的时间。 So first step is to educate (nicely) the DBAs on having the database in archivelog mode, and have RMAN manage online backups.因此,第一步是(很好地)教育 DBA 将数据库置于归档日志模式,并让 RMAN 管理在线备份。

Second, you need to improve the merge criteria so that the merging columns are indexed.其次,您需要改进合并标准,以便对合并列进行索引。 It could well be that dateHappen is indexed, but since you are invoking a function on it in the merge criteria, that index cannot be used unless a function-based index is created.很可能dateHappen已编入索引,但由于您在合并条件中对其调用函数,因此除非创建基于函数的索引,否则无法使用该索引。 I am referring to the我指的是

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

specifically;具体来说; and in general,一般来说,

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

You should check to see if id and field on another_table is indexed, and create a function-based index on dateHappen:您应该检查another_table上的idfield是否已编入索引,并在 dateHappen 上创建一个基于函数的索引:

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

For your database tuning, just invoke the merge statement by itself in a SQL tool to try different approaches;对于你的数据库调优,只需在SQL工具中自行调用merge语句,尝试不同的方法即可; then you won't have to worry about killing merges half-way, whicn would be causing a lot of work in the database rolling back transactions, etc.那么你就不必担心中途杀死合并,这会导致数据库回滚事务等大量工作。

Update:更新:

OK, I will answer the question instead of providing my solution.好的,我会回答问题而不是提供我的解决方案。 :) :)

You can create a profile that is then assigned to a user to limit sessions to a specific CONNECT_TIME or IDLE_TIME or both.您可以创建一个profile ,然后将其分配给user以将会话限制为特定的CONNECT_TIMEIDLE_TIME或两者。 Then if the user exceeds the time, according to http://docs.oracle.com/database/121/SQLRF/statements_6012.htm#SQLRF01310那么如果用户超过了时间,根据http://docs.oracle.com/database/121/SQLRF/statements_6012.htm#SQLRF01310

If a user exceeds the CONNECT_TIME or IDLE_TIME session resource limit, then the database rolls back the current transaction and ends the session.如果用户超过 CONNECT_TIME 或 IDLE_TIME 会话资源限制,则数据库回滚当前事务并结束会话。 When the user process next issues a call, the database returns an error.当用户进程下一次发出调用时,数据库返回一个错误。

So you can do this:所以你可以这样做:

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

Then when your session is created, if the session is idle for 5 minutes, Oracle will kill the session, and if it is running solid for 24 hours, (running commands with less than 5 minutes between commands for 24 hours) Oracle will kill the session.然后当你的会话创建时,如果会话空闲 5 分钟,Oracle 将终止该会话,如果它稳定运行 24 小时,(运行命令之间的命令间隔少于 5 分钟,持续 24 小时)Oracle 将终止该会话会议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM