我的问题
在我的日志中,我看到了一些System.OutOfMemoryException错误在负载测试期间被记录下来。它们来自于一个Dapper查询。根据堆栈跟踪,当列表被调整大小时发生错误。
堆栈跟踪的顶部
System.OutOfMemoryException: 异常类型'System.OutOfMemoryException'被抛出。 at System.Collections.Generic.List
1.set_Capacity(Int32 value) at System.Collections.Generic.List
1.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更具调整大小/内存友好性的不同集合吗?