调用Dapper的QueryAsync<>()方法时出现System.OutOfMemoryException异常。

3

我的问题

在我的日志中,我看到了一些System.OutOfMemoryException错误在负载测试期间被记录下来。它们来自于一个Dapper查询。根据堆栈跟踪,当列表被调整大小时发生错误。

堆栈跟踪的顶部

System.OutOfMemoryException: 异常类型'System.OutOfMemoryException'被抛出。 at System.Collections.Generic.List1.set_Capacity(Int32 value) at System.Collections.Generic.List1.AddWithResize(T item) at Dapper.SqlMapper.QueryAsync[T](IDbConnection cnn, Type effectiveType, CommandDefinition command) in C:\projects\dapper\Dapper\SqlMapper.Async.cs:line 442

正在调用的代码

const string sql = $@"
  SELECT [Column 1]
        ,[Column 2]
        ,[Column 3]
        ,[Column 4]
        ,[Column 5]
        ,[Column 6]
        ,[Column 7]
        ,[Column 8]
        ,[Column 9]
        ,[Column 10]
        ,[Column 11]
        ,[Column 12]
    FROM [MyDb].[MyTable]
    WHERE co = @CompanyId AND process = @Process
    ";

await using var connection = _dbConnectionProvider.Create(DbKey.MyDb);

var parameters = new { CompanyId = CompanyDbString(companyId), Process = process };
var command = new CommandDefinition(sql, parameters);
var results = await connection.QueryAsync<MyEntity>(command); // error happens here

return results;

关于正在加载的数据的一些信息

我查看了数据库,并发现所涉及的数据大小为141,846行。这些列没有什么“特别之处”(没有巨大的文本块或类似的东西),只是一些合理的varchars、datetimes、ints等。所有的varchars最大长度为100个字符。

并且为了避免不可避免的“你真的需要加载所有这些数据吗?”的评论:是的,我需要。

可能的解决方案?

因此,正在加载的数据是一个相当大的数据集,但并没有太疯狂。我很惊讶它会耗尽内存。我觉得特别有趣的是,异常源自于System.Collections.Generic.List1.set_Capacity(Int32 value)。基于这个,看起来错误发生在列表调整其内部数组大小的时候。

我的第一个想法是分页结果,就像在这里建议的那样:https://stackoverflow.com/a/52212051

然而,我不确定这是否有效,因为它仍然依赖于添加到列表中。这是一个有效的问题吗?如果是,那么首先获取计数并以该计数作为初始容量开始列表是否是一个好方法?

或者,也许有一种比List更具调整大小/内存友好性的不同集合吗?

1个回答

3

你需要执行一个未缓存的Dapper查询,并将结果插入到预先调整大小的列表中。

var list = new List<MyEntity>(someBigSizeHere);
var command = new CommandDefinition(sql, parameters) { Buffered = false };
using var results = await connection.QueryAsync<MyEntity>(command);
list.AddRange(results);
return list;

请注意,在关闭连接之前,您必须确保完全阅读并处理results
如果在此之后仍然出现内存溢出异常,则表示您的数据过多。尝试编译为64位并在系统中添加更多RAM。或者更好的方法是,重新考虑您为什么需要这么多数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接