将大量数据加载到C# GridView中出现性能问题

4

好的,

我一直在将相对较小的数据集测试到我的GridView中,并且一切正常。但是,现在我已经进入了适当的UAT并尝试将17,000条记录加载到我的Grid中,这基本上让我的网络应用程序停滞不前。

基本上,用户登录后,在验证完成后所有数据网格都会加载,其中一个包含17k条记录。在一切加载完成之前,最终用户将悬挂在登录页面上。所以我需要解决它。

Grids的代码如下:

DataTable dtValueDateCurrency = null;               
SqlConnection conn = new SqlConnection(WebConfigurationManager.ConnectionStrings["Reporting"].ConnectionString);
using (conn)
{
    conn.Open();
    //Load all other grid data
    using (SqlDataAdapter sqlAdapter = new SqlDataAdapter(TSQL1, conn))
    {
        dtValueDateSummary = new DataTable();
        sqlAdapter.Fill(dtValueDateSummary);
        grdValueDateSummary.DataSource = dtValueDateSummary;
        grdValueDateSummary.DataBind();
    }
 }

有没有办法提高加载速度?分页不是一个选项,因为我正在使用 JQuery 处理此问题。

4
不要从数据库加载17k条记录,而要使用数据库分页功能(例如通过“ROW_NUMBER”函数)。不要将太多记录绑定到您的GridView中,而应该使用服务器端分页而不是jquery。您是否查看过生成的HTML?那么您就会知道为什么它很慢。 - Tim Schmelter
不要将大数据集加载到C# GridView中,以避免性能问题。 - Chase Florell
通过使用数据读取器而不是数据适配器从数据库中添加记录,可能会获得稍微更好的响应。我理解这对于大型数据集来说更好。基本上,您将手动填充数据表...当它调用gridview.bind()时,仍然会有一些性能损耗。 - logixologist
1
根据您对这里答案的评论,让我更加通俗易懂:永远不要尝试在网络上加载17,000条记录。这不是“GridView”问题,也不是“DataReader”与“DataAdapter”的问题。这只是一页上信息太多了。这必须在服务器上处理。您将不得不改变分页和过滤选项的工作方式,但它们仍将起作用。 - jwheron
5个回答

6

一次查询加载17,000条记录是导致问题的主要原因。我强烈建议在GridView中使用分页。

首先,您需要按以下方式修改存储过程。

ALTER PROCEDURE [dbo].[SomeTable_GetPagedResults] 
( 
        @StartRowIndex      int, 
        @MaximumRows        int 
) 

AS 
SET NOCOUNT ON 

Select 
    RowNum, 
    [ID], 
    [foo],
    [bar]
From 
    (Select 
        [ID], 
        [foo], 
        [bar], 
        Row_Number() Over(Order By [ID] Desc) As RowNum 
        From dbo.[SomeTable] t) 
As DerivedTableName 
Where RowNum Between @StartRowIndex And (@StartRowIndex + @MaximumRows) 

现在你已经拥有可分页的查询。同时,你也需要一个用于获取完整行数的查询。
ALTER PROCEDURE [dbo].[SomeTable_GetRowCount] 

AS 
SET NOCOUNT ON 

return (Select Count(ID) As TotalRecords From SomeTable) 

每次更改页码时,您都需要绑定网格。

protected void gridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
  gridView1.PageIndex = e.NewPageIndex;
  BindGrid(); // this is whatever method you call to bind your data and execute your stored procedure.
}

BindGrid() 方法会调用两个存储过程(一个用于获取完整行数,另一个用于获取当前页面的结果)。

更多阅读


1
为什么不能两者兼顾呢?你不可能认真地在单个页面上展示所有的17000条记录吧。谁会在那样的混乱中拖放任何东西呢?我认为你需要重新考虑你的方法。 - Chase Florell
2
我觉得这种方法不太好。更好的方法是通过AJAX调用服务器并传递筛选条件,然后启用分页功能将结果反馈到应用中。 - Chase Florell
1
这个答案仍然在每次调用时检索所有的17,000条记录,只不过现在它只显示一页的数据。 - Garrison Neely
1
你可以切换到 Repeater,但肯定是数据而不是标记在拖慢了事情。 - Garrison Neely
2
我不想再强调这一点,但.NET仍然需要将这些记录处理成内存中的对象,这可能不一定需要1-2秒钟。不过你有代码,可以进行测试,所以在这一点上我听从你的意见。 - Garrison Neely
显示剩余11条评论

2
你需要实现数据库分页。
这将涉及创建自定义排序、自定义过滤和自定义分页,但它将显著提高您的代码性能,因为您每次从数据库中检索到的只是一页数据,而不是一次检索所有17,000行数据。
我在一个银行应用程序中实现了这个功能,该应用程序旨在显示、排序和过滤数十万笔贷款。答案太复杂了,无法给出简单的示例,但可以通过研究数据库分页来开始。使用LINQ,它将为您提供简单的Take和Skip方法来实现最简单的分页。

1
你应该考虑在Web服务器上缓存查询,特别是当它很少更新时。这样,所有客户端都可以简单地从缓存中浏览,而不是无情地访问数据库。
请参见这个SO问题

1
这并没有解决对17000条记录的初始调用。分解请求(分页/惰性加载)是解决此问题的唯一方法。 - Chase Florell
他可以在 Application_Start 中将其加载到缓存中。 - Garrison Neely
@GarrisonNeely 这是一个想法。 - CSharpNewBee
更不用说,一旦他使用了jQuery的拖放功能,缓存就需要完全更新以反映这些更改。 - Chase Florell
我恐怕他不能两全其美——既坚持使用jQuery来管理整个数据集,又能够执行花哨的查询。 - Jesse Smith
显示剩余3条评论

0
实际上,一次加载17k条记录并不实用,即使用户无法一次看到所有17k条记录。我建议您使用分页和DataTable.Merge函数一起使用,这有助于将记录分块加载,并将新获取的数据附加到以前的数据中。我刚刚进行了快速测试并找到了一个解决方案。试试这个。

-1

没有解决方案,分页很慢,会不断地调用数据库, 所以你需要 放置

<style>.body{display:none;}</style>

页面开始处和页面结尾处

<style>.body{display:block;}</style>

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