вторник, 21 юли 2009 г.
These days I have been working on a very interesting project here at National Academy for Software Development. I had to make a performance audit of a project on which two or three development teams have been working on previously.
- The used technologies were .NET Framework 3.5, C# 3.0, ASP.NET 3.5, SQL Server 2005, LINQ and LINQ to SQL.
- 2-tier architecture.
- The coding style – very different (different dev teams from different parts of the world).
- The used practices – hard to find after so many patches.
- The performance – poor.
I’m preparing a short series of posts about the problems, which I could be found in this software as well as in many others. As you will see below not all of the problems could be fixed. However most of them could be and you can think of them as something which you should definitely avoid. I’ll provide you with some set of advices how to find/avoid such problems. They will include tools and practices which will help you to provide more robust and reliable software. I will be very happy to “hear” your comments about the written as well as your personal experience with similar problems.
Let’s start our performance journey with the first topic!
Shit of the Day: DataPager Binds Twice
While I was observing the behavior of one of the pages which seems to have problems, I found something very “interesting”. Firstly, let me give you some necessary info about this particular situation. The page had a ListView control, DataPager associated with it and ObjectDataSource against which the ListView was bound. As you know, the ObjectDataSource provides two properties – SelectMethod and SelectCountMethod which retrieve respectively the items with which the list will be bound as well as their count. Of course the data source should know also which class provides these methods, so there is also property called TypeName. You know that for the paging functionality we should be able to “ask” how many records are there as well as “give me the i-th page”. This in theory means that we should make two DB queries to “ask” these two questions.
But what happened in practice? I found that the select method and the count method were called twice. My first suspicion was that the control was bound twice. I start inspecting the code line by line searching for such thing. After a few minutes of debugging I convinced myself that the list was bound only once. The next step was to review the DAL (Data Access Layer) logic for potential problems. Again - nothing which could cause this behavior…
In such situation the only thing which could be done is googling. I searched for a while and found the following article from a Microsoft’s site – “DataPager double binds when paging using QueryStringField” which was confirmed to be a bug. I’ve quickly checked whether QueryStringField is used in my situation and voila – the problem was dissected.
The short description about this bug is: “When you use the QueryStringField with a DataPager it causes the ListView to bind twice; once as if it was on the first page, and a second time for whatever page is passed via the QueryString (even if it is also the first page). Naturally, this is very bad for performance and completely unnecessary.”
Currently Microsoft hasn’t provided any workarounds for this problem. So just try to avoid using this particular combination in your projects.
When you are developing particular page/control always check the queries which are made against your database both for loading and storing data. When using ORM frameworks such as LINQ to SQL it is very important to know exactly what queries are executed against your DB. You could use frameworks like Log4Net/Microsoft Enterprise Library Logging Application Block along with DataContext.Log property. You should definitely use (if not already) classes like this for outputting LINQ to SQL queries to the debugger output. These very simple practices will save your live from similar shit of the day.
Stay tuned and have fun!