September 2004 - Posts

Mono, Whidbey, performance, Yukon, and Lima

This has been an hectic day, it started at 7:30 AM when we did a breakfast for a few really Microsoft-reluctant friends about Project Mono, it went well but I had to leave the event in the hands of my OSS-prone partners because I had to start at 9:00 AM a presentation to a very big local ISV who's deciding whether to rewrite their successful VB 6.0 systems in J2EE or .NET, allegedly the presentation was going to focus on multi-tiered distributed architectures but it briefly derived into an ASP.NET 2.0 presentation and then in an intense Q&A about application servers, COM+ and Indigo. At 11:00 I had to go to my office just to sign some papers and then run to another customer to discuss some severe performance problems they are having in a distributed application, the culprit: a number of fine grained remoting components that move some heavy datasets, the solutions that we started to implement was: a) cache the datasets in the client, b) coarse the interfaces, c) add a ziping sink to the remoting stack, d) download the datasets in a background thread. Then at 1:00 PM I had a lunch with an old friend and customer and discuss some future .NET projects and again Mono (they are currently a Java and Powerbuilder shop). At 3:00 PM I had a rush meeting (on a car, on the way to the airport) with a small ISV that is sending me to Lima, Perú to help them in selling its ASP.NET solution to a big company there. In the plane I unexpectedly run into a colleague who puts me uptodate in his successful .NET project. At 8:00 PM I am at Lima, talk by phone with Jorge Oblitas, the Peruvian RD, and I end up giving a talk about Visual Web Developer 2005 and SQL Server 2005 to some 20 people in a local university. At 10:30 PM we go to dinner with Jorge, and I finally leave technology behind as we have a long and pleaseant conversation with the owner of a chinese restaurant. I really feel happy about this day yet I hope I won't have a day like this in a few moons...

Webcasts and coincidences

In my last post, just minutes ago, I mentioned the code blocks and how a webcast was helpful in a real work situation. Well, I just received an e-mail inviting me to a webcast about Enterprise Library, the double coincidence comes from the fact that EL is the successor of many of the application blocks that I suggested using in that post. "This must be more than a I coincidence" I instantly thought, so I am blogging again to recommend you joining this webcast (besides, I have managed to show you how I can redundantly overuse hyperlinks).

Posted by Edgar Sánchez with no comments

UAB

A few days ago a customer called us with a specific problem: they have developed a pretty big application with Windows Forms and MBI (a framework for building business layers), now that they were about going live they needed to solve the problem of having relatively frequent updates of their Windows Forms client. After reviewing their scenarios, it was clear that the most adequate (or less troublesome) solution was to use the Updater Application Block. It's interesing how in situations like this it's always tempting to write your own solution, especially because the use of components like UAB is not trivial and requires several hours to understand well enough. Luckily, for UAB it helped me a lot the webcast that Chris Kinsman did in August on the subject. Having the source code was also helpful as one need of my customer was that the manifest file didn't get deleted after being downloaded from the deploy server: it took us half an hour to find the place inside UAB where this was done and parameterize the code with an entry in the configuration file. In retrospect, the 6 or 8 hours that we had to invest were far less than those we would've used in writing our own solution; that is why I suggest you to use the code blocks: the effort that takes to learn them usually pays handsomely.

Posted by Edgar Sánchez with 1 comment(s)

OO Numerical Methods in C# 2.0

In his book Object-Oriented Implementation of Numerical Methods: An Introduction with Java & Smalltalk, Didier Besset presents some of the most useful numerical algorithms; one interesting theme on the book is that Didier concentrates more in using the object oriented paradigm so as to get an easy to use and extensible set of classes than in getting the maximum possible performance. As expected from the title, the book presents detailed code in Java and Smalltalk, I have tried and translated the code to C# using Visual Studio 2005 Express Edition. Even though I have used very little of C# 2.0 new features (the code will run with minimal changes in C# 1.0), the exercise let me find out how stable and usable is the new IDE (impressive in both points). You can finally download the code here, even though the unit test set I have used is patetically small, at least the code compiles and passes it.

Posted by Edgar Sánchez with 1 comment(s)
Filed under:

Simple optimizing pleasures

Sometimes you have an entertaining half an hour of good old simple tuning, for example this afternoon I had to consider this stored procedure (the names of the variables have been changed to protect the innocent): 

CREATE PROCEDURE COUNTER_VALUE (@TAB AS VARCHAR(50),@CNT INT OUTPUT)AS

DECLARE @VALUE INT

       SET NOCOUNT ON

       BEGIN TRANSACTION COUNTER

       UPDATE COUNTERS SET CUR_VALUE = CUR_VALUE + 1 WHERE TABLE_NAME = @TAB

       SELECT @VALUE = CUR_VALUE FROM COUNTERS WHERE TABLE_NAME = @TAB

       IF @@ERROR <> 0

       BEGIN

              ROLLBACK TRANSACTION COUNTER

              SELECT @CNT = -1    

              RETURN

       END

       ELSE

       BEGIN

              COMMIT TRANSACTION COUNTER

              SELECT @CNT = @VALUE      

              RETURN

       END

 Allegedly, this sproc is used to get successive numbers for many tables in the database. This database is suffering of performance problems and, as this sproc is used in many places, we should try and boost its performance. Let’s do it step by step:

 

  1. Measure: calling the sproc a thousand times takes 6.2 seconds
  2. Review your design: someone may point out that instead of using this sproc you could use an IDENTITY column. Certainly this would kill all problems with the sproc but in my case such a change would force changes in many places of the system: too risky. Conclusion: as you design and develop your system test for performance or else you may find that you are not able to apply tunings that are obvious
  3. Check your indexes: it so happens that the COUNTERS table has a non-clustered index on the TABLE_NAME column (which is the primary key.) Given that the COUNTERS table has only a few dozen rows, the index shouldn’t matter that much but anyway I tried clusterizing the index.
  4. Measure: calling the sproc a thousand times takes 2.7 seconds. A 229% improvement!
  5. Check your SQL: why is it that I have to do a SELECT after the UPDATE? To get the new value of course, but we can collapse these two statement:

UPDATE COUNTERS SET CUR_VALUE = CUR_VALUE + 1 WHERE TABLE_NAME = @TAB

SELECT @VALUE = CUR_VALUE FROM COUNTER WHERE TABLE_NAME = @TAB

       Into this:

UPDATE COUNTERS SET @VALUE = CUR_VALUE = CUR_VALUE + 1 WHERE TABLE_NAME = @TAB

  1. Measure: calling the sproc a thousand times takes 1.2 seconds. A 516% improvement over the original measurement!
  2. Reconsider your SQL: now why is that we need an internal transaction. Furthermore, what can go wrong in the one and only SQL statement left? So lets simplify the sproc to this:

CREATE PROCEDURE sp_COUNTER_VALUE (@TAB as varchar(50),@CNT int OUTPUT)AS

       SET NOCOUNT ON

       UPDATE COUNTERS SET @CNT = CUR_VALUE = CUR_VALUE + 1 WHERE TABLE_NAME = @TAB

  1. Measure: calling the sproc a thousand times takes 1.3 seconds. And actually it’s a little slower than the previous version, funny. After some tweaking I settle for this:

CREATE PROCEDURE sp_COUNTER_VALUE (@TAB as varchar(50),@CNT int OUTPUT)AS

DECLARE @VALUE INT

       SET NOCOUNT ON

       SET @VALUE = -1

       UPDATE COUNTERS SET @VALUE = CUR_VALUE = CUR_VALUE + 1 WHERE TABLE_NAME = @tab

       SELECT @CNT = @VALUE

  1. Measure: calling the sproc a thousand times takes 1.2 seconds. At least I am back to my previous mark and the procedure is simpler.

 

Lessons learned:

  1. Don’t design without checking the performance consequences
  2. Check the design, check the indexes and only then tweak your logic
  3. Measure before and after. Don’t trust your experience or hunches: measure.

 And that’s enough because we don’t want performance just for the sake of it. A 500% enhancement is already great and now it’s time to check other parts of the system.

Posted by Edgar Sánchez with 2 comment(s)
More Posts