C# 巨大的列表性能和内存消耗
我正在启动一个新的应用程序。我对数据库运行查询,然后返回一个自定义对象列表。以下是一个例子: 用这个方法我得到一个表的所有记录。示例:从PKR_PLAYER中选择ID、名称、姓氏C# 巨大的列表性能和内存消耗,c#,.net,performance,list,ado.net,C#,.net,Performance,List,Ado.net,我正在启动一个新的应用程序。我对数据库运行查询,然后返回一个自定义对象列表。以下是一个例子: 用这个方法我得到一个表的所有记录。示例:从PKR_PLAYER中选择ID、名称、姓氏 public List<TEntity> GetAll() { List<TEntity> all = new List<TEntity>(); String query = String.Format("SELECT {0} FROM {1}",AllFieldsS
public List<TEntity> GetAll()
{
List<TEntity> all = new List<TEntity>();
String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
{
all.Add(CreateOneFromRecord(record));
}
return all;
}
public List GetAll()
{
List all=新列表();
String query=String.Format(“从{1}中选择{0}”,AllFieldsSelection,TableName);
var data=SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach(SqlServerUtils.GetRecords(数据)中的IDataRecord记录)
{
添加(CreateOneFromRecord(record));
}
全部归还;
}
通过这个,我创建了一个TEntityObject,其中的数据存储在记录中
private TEntity CreateOneFromRecord(IDataRecord record)
{
var result = new TEntity();
for (int i = 0; i < record.FieldCount; i++)
{
ColumnMap colMap = maps.FirstOrDefault(x => x.Column.Equals(record.GetName(i)));
if (colMap == null || record.IsDBNull(i)) continue;
object value = record.GetValue(i);
colMap.PropertyInfo.SetValue(result, value, null);
}
return result;
}
private TEntity CreateOneFromRecord(IDataRecord记录)
{
var结果=新的tenty();
对于(int i=0;ix.Column.Equals(record.GetName(i));
如果(colMap==null | | record.IsDBNull(i))继续;
对象值=记录.GetValue(i);
colMap.PropertyInfo.SetValue(结果,值,null);
}
返回结果;
}
如何执行查询
public static IEnumerable<IDataRecord> GetRecords(SqlExecutionData data)
{
using (SqlConnection sqlConnection = new SqlConnection(data.ConnectionString))
using (SqlCommand command = new SqlCommand(data.Query, sqlConnection))
{
if (data.Parameters!=null && data.Parameters.Count > 0)
{
foreach (String key in data.Parameters.Keys)
command.Parameters.AddWithValue(key, data.Parameters[key]);
}
sqlConnection.Open();
using (IDataReader rdr = command.ExecuteReader())
{
while (rdr.Read())
{
yield return (IDataRecord)rdr;
}
}
sqlConnection.Close();
}
}
公共静态IEnumerable GetRecords(SqlExecutionData数据)
{
使用(SqlConnection SqlConnection=newsqlconnection(data.ConnectionString))
使用(SqlCommand=newsqlcommand(data.Query,sqlConnection))
{
if(data.Parameters!=null&&data.Parameters.Count>0)
{
foreach(数据中的字符串键。参数。键)
command.Parameters.AddWithValue(key,data.Parameters[key]);
}
sqlConnection.Open();
使用(IDataReader rdr=command.ExecuteReader())
{
while(rdr.Read())
{
收益率回报率(IDataRecord)rdr;
}
}
sqlConnection.Close();
}
}
简言之,其思想是迭代SqlDataReader(使用yield-return)并创建一个实体,最后将其存储在列表中
我认为这会消耗很多资源。查询返回大约22k条记录,并且经常调用GetAll方法。有时会每隔1或2分钟调用一次GetAll方法
我只执行了几次(大约10次)GetAll方法,windows任务管理器上的信息显示内存在几秒钟内从17MB增长到45MB
我相信这个代码不是性能
问题是:如何使代码消耗更少的内存?可能我必须更改列表,但是有什么替代方案呢?您可以使用
收益回报率
,但是您需要稍微更改一下您的方法。这将最大限度地减少内存消耗
public IEnumerable<TEntity> GetAll()
{
String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
{
yield return CreateOneFromRecord(record);
}
}
public IEnumerable GetAll()
{
String query=String.Format(“从{1}中选择{0}”,AllFieldsSelection,TableName);
var data=SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach(SqlServerUtils.GetRecords(数据)中的IDataRecord记录)
{
收益返回CreateOneFromRecord(记录);
}
}
这将消耗更少的内存,但也将保持与SQL Server的连接打开。
请阅读更多信息。您可以使用
收益回报率
,但您需要稍微改变一下方法。这将最大限度地减少内存消耗
public IEnumerable<TEntity> GetAll()
{
String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
{
yield return CreateOneFromRecord(record);
}
}
public IEnumerable GetAll()
{
String query=String.Format(“从{1}中选择{0}”,AllFieldsSelection,TableName);
var data=SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);
foreach(SqlServerUtils.GetRecords(数据)中的IDataRecord记录)
{
收益返回CreateOneFromRecord(记录);
}
}
这将消耗更少的内存,但也将保持与SQL Server的连接打开。
请阅读更多信息。另一个选项是委派每个项目。 这是更明确的,您对每个项目都有更多的控制权。 但是您需要小心,委托调用将阻止迭代。 我更喜欢使用IEnumerable,因为它在.NET中有很多特性(PLinq、foreach、Collection等) 收集列表中的项目:
public void FillAList()
{
var list = new List<TEntity>();
ProcessItems((index, item) => list.Add(item));
}
public void fillilist()
{
var list=新列表();
ProcessItems((索引,项)=>list.Add(项));
}
另一个选项是委派每个项目。
这是更明确的,您对每个项目都有更多的控制权。
但是您需要小心,委托调用将阻止迭代。
我更喜欢使用IEnumerable,因为它在.NET中有很多特性(PLinq、foreach、Collection等)
收集列表中的项目:
public void FillAList()
{
var list = new List<TEntity>();
ProcessItems((index, item) => list.Add(item));
}
public void fillilist()
{
var list=新列表();
ProcessItems((索引,项)=>list.Add(项));
}
这是否会导致应用程序出现实际问题?如果没有,不要浪费时间解决你没有遇到的问题。数据是否有很多重复的字符串?一些偷偷摸摸的实习可能会有帮助。。。或者:这可能只是数据的必要权重。是否可以在服务器上缓存数据,而不是每分钟请求一次?它多久改变一次?只是出于好奇,为什么在这里使用延迟执行(收益率)?@Oded Hi!谢谢这可能会导致未来的问题。但我的想法是学习如何在这种情况下更好地编写代码这是否会导致应用程序出现实际问题?如果没有,不要浪费时间解决你没有遇到的问题。数据是否有很多重复的字符串?一些偷偷摸摸的实习可能会有帮助。。。或者:这可能只是数据的必要权重。是否可以在服务器上缓存数据,而不是每分钟请求一次?它多久改变一次?只是出于好奇,为什么在这里使用延迟执行(收益率)?@Oded Hi!谢谢这可能会导致未来的问题。但我的想法是学习如何在这种情况下更好地编写代码根据要求,返回的是IEnumerable
,而不是<