我有一个控制台应用程序,我必须一般来说检查整个基地来做东西 ......
为此,我正在使用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天,但问题是我的Foo
和Boo
方法有倍数连接到一个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
组成...基本上我必须用他们的日期跨越那些状态......
所以它在数据库上有很大的延迟...这是一个已知的问题,我们必须重构整个数据库模型....我们很快就会这样做......
但无论如何,尽管有处理时间,但如果我可以管理(或强制)连接终止,那就没关系......
有什么想法吗?
答案 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
上的field
和another_table
是否被编入索引,并在dateHappen上创建基于函数的索引:
create index i_date_string on whatever_table (TO_CHAR(dateHappen, 'DDMMYYYY'))
对于数据库调优,只需在SQL工具中调用merge语句即可尝试不同的方法;然后你不必担心中途杀死合并,这会导致数据库回滚交易等方面的大量工作。
更新
好的,我会回答这个问题,而不是提供我的解决方案。 :)
您可以创建profile
,然后将其分配给user
,以限制与特定CONNECT_TIME
或IDLE_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将杀死会议。