Datagrid Performance - Binding and Rendering

D

David Hirschfeld

CONTEXT: I have build a class called clsGridBuilder that
uses the TemplateColumn class to dynamically build a
datagrid, using the ITemplate.InstantiateIn interface to
dynamically add controls to each tablecell and then
Dynamically binds each cell to an element in a DataTable.

PROBLEM1: It only takes 1-2 seconds to load the
datatable and create the instantiate the grid. However,
it take 7 to 20 seconds or more to bind the datagrid to
the datatable, depending how many elements are in the
grid. Does anyone know any effective techniques to speed
up the process of binding values to a datagrid??? I'm
not married to the datatable. If an arraylist or some
other object would speed up the binding process, I would
like to know about it.

PROBLEM2: It take approximately 5 seconds to render the
page. The page, depending on the number of rows and
columns rendered, ends up to be between 200K and 1.5 meg
in size. This is measured by viewing the page's source
code, copying and pasting it into a .txt file, then
looking at the file size property of the .txt file. There
are no images being rendered, thus there is just a ton of
HTML being output. I have already reduced the page size
a bunch by reducing the ViewState size, but the page is
still way too big. The only other thing I can think to do
is use styles intelligently so that there are fewer
styles and attributes rendered with each tablecell. Does
anyone know of effecient techniques that will help reduce
the size of the datagrid?
 
A

Alvin Bruney

about your only hope there is to reduce the size of the data. you are
dealing with a considerable amount of data so your most immediate benefit
would be to reduce the size of the data being transferred.

for the rendering, if you will page the datagrid, then only one page has to
be rendered as opposed to rendering the entire dataset. The benefit of
paging is immediate and noticable. Some sites use alphabets at the top of
the page A - Z for just that purpose. Clicking on a letter fires a query
which retrieves just that specific dataset. Other sites use custom paging
which gets data one page at a time. The idea behind all this is to reduce
the amount of data moving across the lines.
 
D

David Hirschfeld

I am already paging the data. I have not yet implemented custom paging,
though I plan to. However 75% of the time it takes for the page to
display is associated with databinding and rendering. I only display 20
to 30 records per page. I I'll ask again.
1) Are there any known techniques to speed up custom databinding?

2) Is there any documnetation regarding how to more effeciently use
Style Sheets. I noticed that the datagrid outputs a lot of styles
redundant style text. I will probably build my own style consolidator
if no one can direct me to documentation or techniques to help with this
proble.

My only other alternative is to override (assuming it's even possible)
the binding and rendering logic of the datagrid control. Not a prospect
that I savor.
 
D

David Hirschfeld

I am already paging the data. I have not yet implemented
custom paging,
though I plan to. However 75% of the time it takes for
the page to
display is associated with databinding and rendering. I
only display 20
to 30 records per page. I I'll ask again.
1) Are there any known techniques to speed up custom
databinding?

2) Is there any documnetation regarding how to more
effeciently use
Style Sheets. I noticed that the datagrid outputs a lot
of styles
redundant style text. I will probably build my own style
consolidator
if no one can direct me to documentation or techniques to
help with this
proble.

My only other alternative is to override (assuming it's
even possible)
the binding and rendering logic of the datagrid control.
Not a prospect
that I savor.
 
J

Jeffrey Tan[MSFT]

Hi David,

Thanks for your feedback.
Based on my understanding, your web form datagrid meet the performance
problem. And your bottleneck is not the database data retrieving, but the
web page render and datagrid binding.
Based on my experience, a datagrid with 20-30 records per page should not
have the performance issue. How do you calculate your page render and
datagrid databinding time?
From your problem2, I think your issue may due to big html page size. Does
your big page size due to ViewState? If it is, I think this may due to you
used many web controls on the web form.
If it due to the big viewstate of your datagrid, a not very well way is
disable the datagird's viewstate and do the state management yourself,
which may be very complex.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi David,

I want to provide more information for you:

Usually, too many web controls in the web form will cause many viewstate
generated on HTML, so the redundant overhead is heavy. Especially, each
cell in datagrid is a webcontrol, so you should be careful of number of
controls you used.(Disable all the un-necessary viewstate)

Custom paging will enable you to retrieve only you wanted data part from
databased(Instead of get the whole table), so it will reduce your data
retrieving time.

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
M

Mike Moore [MSFT]

Hi David,

Jeffery and I discussed your questions and we agreed that we have not yet
provided answers to all your questions. We apologize.

Reviewing the thread, we found that you asked four questions:
1) How to speed up the data binding of a DataGrid control?
2) How to reduce the size of the rendered output?
3) How to speed up custom paging?
4) How to reduce the redundancy of style text in the datagrid's output?

My answer to #1 is long, so I'll leave it till last.


***** #4 too many style tags
I suspect that this is related to having lots of controls in the grid. Each
control outputs its own style tags. It may help you to use Cascading Style
Sheet (CSS) classes with each control's CssClass property. For more
information, please see:

* WebControl.CssClass
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemwebuiwebcontro
lswebcontrolclasscssclasstopic.asp

* First browse "Server-side ASP .NET Data Binding, Part 2: Customizing the
DataGrid Control"
http://msdn.microsoft.com/msdnmag/issues/01/04/cutting/default.aspx
Then click on the link to "Figure 5".

* QuickStart Tutorials - Applying Styles to Controls
http://samples.gotdotnet.com/quickstart/aspplus/doc/webtemplates.aspx
You may want to check out the rest of www.gotdotnet.com as well as
www.asp.net.


***** #3 custom paging
You can end up with a data source that contains 10 records because the
database has exactly 10 records. You can also end up with 10 records
because you performed extra work in your query to only select 10 records.
Either way, you have a data source with 10 records.

After you prepare this data source, then you run data binding. At this
point, any extra work involved in selecting the 10 records has already been
completed. The data grid's processing of those records will be the same. It
just binds to 10 records.

Therefore, speeding up custom paging means speeding up how you gather each
page of data. You need to optimize your queries.

I do not have a direct answer on how you can optimize your particular query
since you did not post any details about your query. You may want to post
this particular question to a database newsgroup such as
microsoft.public.dotnet.framework.adonet .

Here is one idea.
With custom paging you need to filter the recordset down to the precise
rows before binding it to the data grid. One approach uses nested SQL
SELECT statements to first filter and then sort the data. This method has
some assumptions including that the data can be sorted and that the sort
columns, taken together, do not have any rows with duplicate values.

Here's a sample nested query that uses the products table in the Northwind
sample database.
select * from (select top 7 productname, quantityperunit from products
where productid < @ProdID order by productid DESC) as inner order by
productid

This will display product information sorted by productid ascending. Since
productid does not have duplicate values, we can use it to filter the query
down to just 7 records. Our inner query reverses the sort order, uses a
specific productid that we have supplied, and gets the next 7 based on the
reverse sort order. Then the outer query puts the sort order back to
ascending for display.


***** #2 rendered output size
First, I'm curious about what data you are displaying in the datagrid. You
wrote that you are already using paging to display a fairly small number of
rows, yet your total page size is very large. Perhaps each row involves a
large amount of data.

I don't have a direct answer. Here are some ideas.

Please turn off ViewState for the entire page. Then browse the page and
check the total page size. This will help show if we need to focus on the
ViewState.

Please set your paging so that it only shows one row. Then set it again so
that is shows two rows. Compare the total page size for both of these to
get an approximation of how much is being sent to the browser for each row.

Please remove the datagrid from your page and browse it. Perhaps there are
other elements on the page that are very large.


***** #1 binding speed
My main suggestions are to experiment with reducing the number of controls
and to avoid using DataBinder.Eval. The following is taken from my post at
http://www.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&selm=GWUW0fl#CHA.
1532%40cpmsftngxa08.phx.gbl.


1)
Can you determine how much time it takes to run the query vs the time it
takes to create the grid? You could test this by filling the DataSet or
creating the DataReader without assigning it to the DataGrid. If the query
is taking too long, then we need to look at your database or query.

2)
Objects take time to create. If you can reduce the number of controls in
your grid, that will improve performance. However, we don't know yet if the
poor performance is directly due to the overhead of creating lots of
controls.

You can partially verify this by using the same data to fill a DataGrid
with no controls. Keep your column templates and the data assignments, such
as: <%# DataBinder.Eval(Container.DataItem, "au_id") %>. The results will
be ugly, but all the data should be present.

Your templates might look something like this:
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "au_id") %>
<%# DataBinder.Eval(Container.DataItem, "au_fname") %>
<%# DataBinder.Eval(Container.DataItem, "au_lname") %>
</ItemTemplate>

If removing the controls solves your performance problem, then look for
ways to reduce the number of controls.

3)
Replace DataBinder.Eval with direct usage of the container object.

OLD: DataBinder.Eval(Container.DataItem, "au_fname")
NEW: Container.DataItem("au_fname")

---
This third idea needs a little more explanation. The Eval function has a
third parameter for formatting which is missing when you use the container
object directly. Putting the formatting back is a problem.

Here are examples for data of type Decimal and Date.

First, with no formatting:
<%# Container.DataItem("price2") %>
<%# Container.DataItem("pubdate")%>

Second, with formatting:
<%# cType(Container.DataItem("price2"),
decimal).ToString("$#,##0.00;($#,##0.00);Zero") %>
<%# Container.DataItem("pubdate").ToShortDateString %>

With no formatting, everything works fine (based on my limited testing).
However, with formatting, a run-time error occurs if the field has a null
value.

When fields may contain nulls and you need formatting, you may find it's
better to use the Eval method while using the container object directly in
all other cases.

If this still leaves you with using Eval in many places, try an experiment
of replacing all these with directly using the container object with no
formatting. This will have ugly output, but it's just an experiment. If
that significantly helps performance, then you may want to run through the
data prior to binding to replace all the nulls. Then you can use the
container object with formatting.

The following code sample uses the container object directly with and
without formatting. It also runs through the data prior to binding in order
to replace nulls. Replacing null dates does not work well. If the field is
of type Date, then you cannot assign it to "blank". Either it is a real
date or it is null (which causes the run-time error). Since I want null
dates to appear as blank in my output, I added an extra text column to my
data and placed the formatted date into that field.

I suspect you will find that running through the data to replace nulls is
slower than using Eval. So, I expect that you will use the container object
directly where possible, while using Eval where required.

This sample includes two integer columns, two decimal columns, and three
date columns to show the difference in output between the UNformatted
columns that allow nulls vs the formatted columns that do not allow nulls.

You will probably need to change the connection string.

SAMPLE -- HTML for the DataGrid

<asp:DataGrid id="DataGrid1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateColumn HeaderText="Text">
<ItemTemplate>
<%# Container.DataItem("au_lname") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Boolean">
<ItemTemplate>
<%# Container.DataItem("contract") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Decimal">
<ItemTemplate>
<%# Container.DataItem("price1") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Formatted Decimal">
<ItemTemplate>
<%# cType(Container.DataItem("price2"),
decimal).ToString("$#,##0.00;($#,##0.00);''") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Integer">
<ItemTemplate>
<%# Container.DataItem("royalty1") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Formatted Integer">
<ItemTemplate>
<%#
cType(Container.DataItem("royalty2"),integer).ToString("#,##0'%';(#,##0'%');
''") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Date">
<ItemTemplate>
<%# Container.DataItem("pubdate") %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Formatted Date">
<ItemTemplate>
<%# Container.DataItem("pubdate2").ToShortDateString %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Pre-formatted Date">
<ItemTemplate>
<%# Container.DataItem("pubdate3") %>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>


SAMPLE -- VB Page_Load for the code-behind

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
If Not IsPostBack Then
Dim queryString As String = "SELECT au_lname, contract, price as
price1, price as price2, royalty as royalty1, royalty as royalty2, pubdate
FROM authors left outer join titleauthor on authors.au_id =
titleauthor.au_id left outer join titles on titleauthor.title_id =
titles.title_id order by au_lname"
Dim connectionString As String = "server='localhost';
trusted_connection=true; Database='pubs'"
Dim sqlAdapter As System.Data.SqlClient.SqlDataAdapter = New
System.Data.SqlClient.SqlDataAdapter(queryString, connectionString)
Dim ds As DataSet = New DataSet()
sqlAdapter.Fill(ds, "MyData")
Dim col As New DataColumn("pubdate2",
System.Type.GetType("System.DateTime"))
ds.Tables("MyData").Columns.Add(col)
col = New DataColumn("pubdate3", System.Type.GetType("System.String"))
ds.Tables("MyData").Columns.Add(col)
Dim dr As DataRow
For Each dr In ds.Tables("MyData").Rows
If dr("Price2") Is System.DBNull.Value Then dr("Price2") = 0
If dr("royalty2") Is System.DBNull.Value Then dr("royalty2") = 0
If dr("pubdate") Is System.DBNull.Value Then
dr("pubdate2") = Date.MinValue
dr("pubdate3") = ""
Else
dr("pubdate2") = dr("pubdate")
dr("pubdate3") = dr("pubdate").ToShortDateString
End If
Next
DataGrid1.DataSource = ds.Tables("MyData")
DataGrid1.DataBind()
ds.Dispose()
sqlAdapter.Dispose()
End If
End Sub


-------
I hope the above helps to answer your questions.

Thank you, Mike
Microsoft, ASP.NET Support Professional

Microsoft highly recommends to all of our customers that they visit the
http://www.microsoft.com/protect site and perform the three straightforward
steps listed to improve your computer's security.

This posting is provided "AS IS", with no warranties, and confers no rights.
 
D

David Hirschfeld

Thanks for your comments, but this really does not help me. I
understand all the basics you discussed. My problem is not with
Viewstate, nor with data retrieval. I have been evaluating the
performance of various sections of code. The culprits are 1)
databinding the individual cell in the datagrid and 2) the time it takes
to render a large page. When I say "Large", I don't mean 100s of rows.
There may only be 20 or 30 rows. I mean the number of bytes of HTML
output to the browser. As I stated in an earlier post, the size of the
html output is several hundred thousand bytes, and only a small
percentage is viewstate.
 
D

David Hirschfeld

I really appreciate the depth of your response.

Some of what I am struggling with is due to the dynamic nature of how
these datagrid are created and the level of sophistication embedded into
them. It is too difficult to explain in these posts. Is there some way
to have a phone discussion? Then I can log you into to this app and
show you what I'm talking about.
 
D

David Hirschfeld

If this is a duplicate post, I appologize.

Thanks for the depth of you response. Is there some way to have a phone
conversation so that I can log you into the app and show you what I'm
talking about. The datagrids are very sophisticated because I'm
generating dynamically from declarative information in a SQL Server
database. To explain how this works is difficult within the context of
a forum post. My email is (e-mail address removed). You can also reach me
at (480) 209-1984. I'm in Arizona.
 
A

Alvin Bruney

Did you get help with this?

Are you using a lot of javascript in this application? If so there are times
when javascript errors will cause a page to virtually stall for a while. In
particular, have a look at your id and name values to make sure they aren't
duplicates. The javascript engine only points out syntax errors, with these
other subtle errors, the browser tries to figure out from context what is
going wrong which can lead to an abnormally long delay.
 
M

Mike Moore [MSFT]

Hi David,

Looking at the nature of this issue, it would require intensive
troubleshooting which would be done quickly and effectively with direct
assistance from a Microsoft Support Professional through Microsoft Product
Support Services. You can contact Microsoft Product Support directly to
discuss additional support options you may have available, by contacting us
at 1-(800)936-5800 or by choosing one of the options listed at
http://support.microsoft.com/default.aspx?scid=sz;en-us;top.

If this is not an urgent issue and your would like us to create an incident
for you and have Microsoft Customer Service Representative contact you
directly, please send email to (remove "online." from this no Spam email
address): mailto:[email protected] with the following
information,
*Include "Followup: <Tomcat IssueID>" in the email Subject.
*Location of the post
*Subject Line
*First Name, Last Name
*MSDN Subscriber ID
*Company name (if any)
*Phone number

Thank you, Mike
Microsoft, ASP.NET Support Professional

Microsoft highly recommends to all of our customers that they visit the
http://www.microsoft.com/protect site and perform the three straightforward
steps listed to improve your computer’s security.

This posting is provided "AS IS", with no warranties, and confers no rights.


--------------------
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top