0

我正在开始一个新的应用程序。我对数据库运行查询,然后返回海关对象列表。这是一个例子:

使用这种方法,我可以获得一个表的所有记录。示例:从 PKR_PLAYER 中选择 ID、名称、姓氏

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;
}

有了这个,我创建了一个 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;
}

我如何执行查询

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();
    }
}

简而言之,这个想法是遍历 SqlDataReader(带有收益返回)并创建一个实体,最后将其存储在一个列表中。

我认为这会消耗大量资源。该查询返回大约 22k 条记录,并且 GetAll 方法将被非常频繁地调用。有时会每隔 1 或 2 分钟调用一次 GetAll 方法。

我只执行了几次(大约 10 次)GetAll 方法,Windows 任务管理器上的信息显示内存在几秒钟内从 17MB 增长到 45MB。

我相信这段代码不是性能。

问题是:我怎样才能使代码消耗更少的内存?可能我必须更改列表,但有什么替代方法?

4

2 回答 2

2

你可以使用yield return,但你需要稍微改变你的方法。
这将最大限度地减少您的内存消耗。

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);
    }
}

这将消耗更少的内存,但它也会使您与 SQL Server 的连接保持打开状态。请阅读有关此 MSDN 文章的更多信息。

于 2012-05-28T17:46:49.423 回答
1

另一种选择可能是委托每个项目。这更加明确,您可以更好地控制每个项目。但是你需要小心,委托调用会阻塞迭代。我更喜欢使用 IEnumerable,因为它在 .NET 中有很多特性(PLinq、foreach、Collection-ctors)。

public void IterateItems(Action<int, TEntity> handler)
{
    String query = String.Format("SELECT {0} FROM {1}",AllFieldsSelection,TableName);
    var data = SqlExecutionData.Create().WithConn(ConnectionString).WithQuery(query);

    var index = 0;   
    foreach (IDataRecord record in SqlServerUtils.GetRecords(data))
    {
        handler(CreateOneFromRecord(index, record));
        index++;
    }
}

内存高效调用:

public void MemoryEfficient()
{
    ProcessItems((index, item) => Console.WriteLine("{0}: {1}", index, item));
}

收集列表中的项目:

public void FillAList()
{
    var list = new List<TEntity>();
    ProcessItems((index, item) => list.Add(item));
}
于 2012-05-29T08:14:56.487 回答