Saturday, April 11, 2009

Using datasets on the C# Compact Framework

I am in the middle of developing a CRM client for mobiles in C# 3.5SP1 with Visual studio 2008 and the after a few weeks of implementation I noticed the performance of the program is bad, and I mean very bad. At first I thought it was the WM5.0 Device emulator that was slowing things down, it uses a ARM cpu so it needs to emulate it completely.

However I had access to a WM5.0 Smartphone device last week and it appears that it the performance is equally bad, so I started investigating what could be the cause of the slowdown. I read on msdn that creating forms with a lot of nested controls could cause a significant slowdown, so I applied the suggested optimizations (creating controls top->down with setting Parent property of the childs and use the Bounds property instead of a combination of Size and Location) but I saw little difference in speed.

I'm using a SQL CE 3.5SP1 Compact database and I already figured that the queries would be the cause, so I started testing the speed and came to some very bad results:

A query SELECT * FROM Entities, with about 5 columns and 3 records took a whopping 1500ms. I was using a generated dataset for the queries, so I checked if the speed would improve if I used the SqlCeConnection with SqlCeCommand manually.

My first implementation was even slower with 2000ms, but this was because I opened & closed the connection each time I called the method, leaving a lot to be desired on speed. SQL CE doesn't support connection pooling, so opening and closing each time was a huge slowdown.

After I wrote a connection pool singleton class (basically a stack with available connections made thread safe) with 2 methods Aqcuire() and Release() which pop & push a connection. I opened them if they were closed at Aqcuire and I leave them opened. I changed my retrieve method with this approach and I got 400ms, which is still pretty bad but a huge optimization from where I started.

I don't know why datasets are so much slower, but they are. So write your queries yourself instead of relying on a dataset with generated code, it's much faster. If you have a lot of queries or a lot of tables in the dataset write your own generator that generates the code for the classes.


It's not much more code if you group the same code parts (such as reading from the SQLCeDataReader) than if you used a datatable, so it's definately worth using if you're focused on performance.