c# – 使用datareader读取数百万个数据时,如何避免数据库连接丢失问题?
作者:互联网
我有一个从数据库表中读取数据的类库.现在这个数据库表是客户端数据库,我的应用程序只有连接字符串和sql查询来打开连接,执行sql查询,读取数据并执行一些操作.
这个操作是什么,它有点复杂(基本上是业务规则).
现在,用户以特定格式提交sql查询,我的类库知道从sql查询结果中选择哪些列.
我不知道我的类库会处理的记录数.它也可能是100,200或数百万的数据.
目前,类库正在处理驻留在oracle上的9000万个数据.我正在使用SQLDATAREADER读取此数据.
现在的问题是避免内存异常我正在使用sql数据读取器读取数据但是逐个读取9千万个数据,然后对每个记录执行一些操作,连接将保持打开状态,目前我面临的问题是连接丢失:
ORA-03135: connection lost contact
1解决方案可能是读取块中的数据,但正如我所说,我不知道我可能正在处理的记录数量,并且SQL查询不在我手中,因为它是由我的类库提取的用户提交的.
有什么办法可以避免连接问题吗?
更新:
public class LongRunningTask : IDisposable
{
public void Start(DbConnection connection, string sql)
{
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandTimeout = 0;
connection.Open();
using (var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
//read 1 by 1 record and pass it to algorithm to do some complex processing
}
}
}
}
算法并不慢,这不是问题.主要问题是读取部分,如果当前来自ORACLE的数据为9千万,则速度很慢.
我已经测试了针对SQL SERVER的1亿个数据,我没有遇到过这个问题(虽然有时会出现传输层错误),尽管这个过程花费了很多时间.我只是在使用ORACLE时遇到了这个问题.
解决方法:
将数据读取器打开数小时并不是一个好主意.即使一切配置正确,线路上某处也可能出现瞬态错误(如您提到的传输层错误).
您可以在客户端代码中添加重试逻辑,以使其更加健壮.执行此操作的一种方法是跟踪上次处理的记录,并尝试在连接失败时重新连接并从该位置“恢复”.
private const int MAX_RETRY = 10;
private const int RETRY_INTERVAL_MS = 1000;
private string lastProcessedPosition = null;
public void Start(string connectionString, string sql)
{
var exceptions = new List<Exception>();
for (var i = 0; i < MAX_RETRY; i++)
{
try
{
if (Process(connString, sql, lastProcessedPosition)) return;
}
catch(Exception ex)
{
exceptions.Add(ex);
}
System.Threading.Thread.Sleep(RETRY_INTERVAL_MS);
}
throw new AggregateException(exceptions);
}
您的Process()方法将重新连接并跳过已处理的行:
public bool Process(string connString, string sql, string resumeFromPosition = null)
{
using ()// init your connection, command, reader
{
if (resumeFromPosition != null)
{
while (dr.Read() && dr.ToPositionString() != resumeFromPosition)
{
// skipping already processed records
}
}
while (dr.Read)
{
// Do your complex processing
// You can do this every N records if accuracy is not critical
lastProcessedPosition = dr.ToPositionString();
}
}
return true;
}
dr.ToPositionString()是一种扩展方法,您可以根据表模式创建一行唯一的行.
标签:c,ado-net,oracle-sqldeveloper 来源: https://codeday.me/bug/20190716/1473780.html