在 C# 中对大型网格视图进行排序内存不足问题
本文关键字:排序 内存不足 问题 视图 网格 大型 | 更新日期: 2023-09-27 18:34:54
我的'高级'程序员将网格数据存储在会话变量中,以便对其进行排序。
每隔一天,我们不得不重新启动服务器,因为它开始挂断。我觉得这是因为所有这些会话变量都在内存中浮动。
这是对数据进行排序的最佳方式吗?是否有最佳实践?我们必须使用存储过程,因为这是他的规则。Web应用程序真的很慢,我对SQL的了解不足以帮助加快速度。
关于会话变量是否是要走的路的任何想法?有没有更好的方法?
加载数据方法
SqlConnection conn = new SqlConnection (ConfigurationManager.AppSettings ["ConnectionString"].ToString ());
SqlCommand cmd = conn.CreateCommand ();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "RandomStoredProdcedureName";
try
{
DataTable GridData = new DataTable ();
conn.Open ();
using (SqlDataAdapter Sqlda = new SqlDataAdapter (cmd))
{
Sqlda.Fill (GridData);
}
//Persist the table in the Session object. (for sorting)
Session ["GridData"] = GridData;
gvDetails.DataSource = GridData;
gvDetails.DataBind ();
}
catch (Exception ex)
{
Removed for brevity
}
finally
{
if (conn != null) {
conn.Close ();
}
}
排序方法
protected void gvDetails_Sorting (object sender, GridViewSortEventArgs e) {
//Retrieve the table from the session object.
DataTable GridData = Session ["GridData"] as DataTable;
if (GridData != null) {
//Sort the data.
GridData.DefaultView.Sort = e.SortExpression + " " + GetSortDirection (e.SortExpression);
gvDetails.DataSource = GridData;
gvDetails.DataBind ();
}
}
用户查看的记录数不可能超过网格显示的行数 - 如果您的网格有 25 行,则任何超过 25 行的内容都是浪费内存/CPU 时间来处理。(请记住,这些数字不是"绝对的" - 某些应用程序可能需要更多行,有些可能需要更少。它还取决于用户查看数据并理解数据的程度。有些用户一次处理几行效果更好,有些用户需要多行 - 这甚至可能是用户偏好,但底线是拉取一个巨大的结果集几乎总是浪费。
在给定时间从数据库中提取的数据不应超过网格中可以显示的行数。排序应在数据库中完成,以便您只能返回实际需要的行子集。这最大限度地减少了 Web 服务器和数据库服务器之间的网络流量,并最大限度地减少了 Web 服务器上的内存使用,因为您只将数据存储在实际需要的视图/会话状态中。
如果使用视图状态来存储数据(这比使用Session
更好,因为只要用户使用网格查看特定页面,您就会存储数据(,则该数据将发送到浏览器 - 您还将以这种方式最小化 Web 服务器和浏览器之间的网络流量。
如果用户尝试以不同的方式对数据进行排序或转到另一个页面,只需重复上述过程并根据新的页面索引和/或新的排序字段抓取新行。
编辑:
我刚刚注意到您在问题下添加了一条评论,即您通常有 15 个用户并返回 50-1000 行。除非您的 Web 服务器内存非常少(或者除非数据库中的行很大(,否则不太可能导致内存不足错误。是否在会话变量中存储其他大型结果集?
我认为排序可以在SQL中完成。但我们也必须看到 SP。我从不将数据表保留在会话中,我认为这不是一个好方法。
如果数据太大,无法在开发人员每次需要时从数据库中获取数据,他/她可以创建一个视图并从该视图中获取数据。它会快得多
只需改用视图状态即可。
ViewState["GridData"] = GridData;
如果您能告诉我们网格的大小,也会有所帮助?
我看不到数据表的处置位置,您有问题。我的建议是做这样的事情
public void GetData()
{
using(var conn = new SqlConnection (ConfigurationManager.AppSettings ["ConnectionString"].ToString ()))
{
SqlCommand cmd = conn.CreateCommand ();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "RandomStoredProdcedureName";
conn.Open ();
try {
using(var GridData = new DataTable ())
{
using (SqlDataAdapter Sqlda = new SqlDataAdapter (cmd))
{
Sqlda.Fill (GridData);
}
//Persist the table in the Session object. (for sorting)
Session ["GridData"] = CREATE_YOUR_OWN_OBJECTS_FROM_THE_DT(GridData);
}
} catch (Exception ex) {
Removed for brevity
} finally {
if (conn != null) {
conn.Close ();
}
}
}
}
当然有更好的方法来做到这一点,然后你应该实现排序,但我敢打赌问题出在 IDisposable 对象那里根本没有处理过