Kevin Steffer Outloud – web, business and opinions

27Dec/091

Linq, Dataset, Recordset performance result

I’ve for a while now been wondering why I often run into bad performance when using LINQ to access my SQL Server database. So I decided to hunt down the beast and see if I come up with something.

In this first test I haven’t found the beast but I still found some interesting results that I want to share. The result confirms my experience of not using a Dataset to hold data, simply because in most cases it’ll be to time consuming an approach using the SqlDataAdapter Fill method to load a Dataset and here you can see why.

 

 

My test is simply to read out 1,000, 10,000 and 100,000 rows from a simple table and then measure how long it takes to the data out in the three different ways: With LINQ, as a Dataset and as a Recordset from the SQL Server.

Conclusion

The Recordset is twice as fast for small database executions

When working with small amount LINQ isn’t as fast as the Recordset, but in my case it’s now noticeable in a single execution. But when you have to run a lot of small jobs against the database you should keep in mind that the Recordset will do the job twice as fast.

Dataset should be used where many of the same data and used in variety.

When you have to count the number of rows fetched, pray to that you didn’t use the Dataset method. What tares the method down is that it has to load all data with all the properties into the Dataset, just so you can call the Count property on the Rows inside a table on the Dataset object. It just takes way too long time.

With 10,000 rows both LINQ and Recordset is twice as fast as the Dataset

When I increase the rows in the table with factor of 10 to 10,000 rows that test times are rising, which is fair enough because the database sends 10 times more data, but the times are somehow surprising me anyway. The LINQ method rises with a factor 4.5, the Dataset method with a factor of 10 and the Recordset method climes with a factor of 6.5.

With 100,000 rows LINQ begins to catch up with the Recordset

When I further increase the rows in the table with a factor 10 to 100,000 rows I would expect about the same factors, but now they rises even further. The LINQ method rises with a factor 8.7, the Dataset with a factor 9 and the Recordset with a factor 9.5.

Download the Visual Studio 2008 Project

Test system

Hardware: Laptop HP Elitebook, 3GB RAM, 2,53GHz Intel Core Duo, 32bit
Software: Windows 7 32bit, SQL Server Express 2009, Visual Studio 2008 Professional Developer Web Server

Test scenario

I have separated my test into 4 scenarios and each scenario is run 10 times with the same method to get an average value of the time consumption for my conclusion.

LINQ measure method

private void DoLinqTest()
{
    DateTime dtLinqStart = DateTime.Now;
    using ( DB.dbDataContext db = new DB.dbDataContext() )
    {
        // Execution code
    }
    DateTime dtLinqEnd = DateTime.Now;
    lblLinqTime.Text = ( dtLinqEnd - dtLinqStart ).ToString();
}

Dataset measure method

private void DoDataSetTest()
{
    DateTime dtDsStart = DateTime.Now;
    using ( SqlConnection dbCon = new SqlConnection( ConfigurationManager.ConnectionStrings[ "dbConnectionString" ].ConnectionString ) )
    {
        using ( SqlDataAdapter sqlAdap = new SqlDataAdapter( "SELECT * FROM item", dbCon ) )
        {
            DataSet ds = new DataSet();
            sqlAdap.Fill( ds );

            // Executing code
        }
    }
    DateTime dtDsEnd = DateTime.Now;
    lblDsTime.Text = ( dtDsEnd - dtDsStart ).ToString();
}

Recordset measure method

private void DoRecordSetTest()
{
    DateTime dtRsStart = DateTime.Now;
    using ( SqlConnection dbCon = new SqlConnection( ConfigurationManager.ConnectionStrings[ "dbConnectionString" ].ConnectionString ) )
    {
        dbCon.Open();
        using ( SqlCommand sqlCmd = new SqlCommand( "SELECT * FROM item", dbCon ) )
        {
            using ( SqlDataReader rs = sqlCmd.ExecuteReader() )
            {
                // Executing code
            }
        }
    }

    DateTime dtRsEnd = DateTime.Now;
    lblRsTime.Text = ( dtRsEnd - dtRsStart ).ToString();
}

1. Scenario

A test which seen in Testresult Sheet: 1000 List to get out a 1000 database rows as objects of type:

public class item
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime Date { get; set; }

    public item()
    {
    }

}

Executing LINQ code:

List<item> objItems = ( from itm in db.items
                        select new item
                        {
                          Id = itm.id,
                          Name = itm.name,
                          Description = itm.description,
                          Date = itm.date.Value
                        } ).ToList();

Executing Dataset code:

List<item> items = new List<item>();
DataRow[] drs = ds.Tables[ 0 ].Select();
for ( int i = 0; i < drs.Length; i++ )
{
    object[] dbFields = drs[ i ].ItemArray;
    item itm = new item();
    itm.Id = ( int )dbFields[ 0 ];
    itm.Name = dbFields[ 1 ].ToString();
    itm.Description = dbFields[ 2 ].ToString();
    itm.Date = ( DateTime )dbFields[ 3 ];
    items.Add( itm );
}

Executing Recordset code:

List<item> items = new List<item>();
while ( rs.Read() )
{
  item itm = new item();
  itm.Id = rs.GetInt32( 0 );
  itm.Name = rs.GetString( 1 );
  itm.Description = rs.GetString( 2 );
  itm.Date = rs.GetDateTime( 3 );
  items.Add( itm );
}

2. Scenario

A test as seen in Testresult sheet: 1000 Count to get out the amount of rows fetched on a database table with a 1,000 rows.

Executing LINQ code:

int count = ( from itm in db.items
              select new item
              {
                Id = itm.id,
                Name = itm.name,
                Description = itm.description,
                Date = itm.date.Value
              } ).Count();

Executing Dataset code:

int count = ds.Tables[ 0 ].Rows.Count;

Executing Recordset code:

int count = 0;
while ( rs.Read() )
{
    count++;
}

3. Scenario

A test as seen in Testresult sheet: 10000 List with the same Executing code like the 1. Scenario, but this time with having 10,000 database rows to get out.

4. Scenario

A test as seen in Testresult sheet: 100000 List with the same Executing code like the 1. Scenario, but this time with having 100,000 database rows to get out.

Testresult

Download the Visual Studio 2008 Project

Filed under: .NET, ASP.NET 1 Comment
29Oct/090

Add Reference Dialog Improvements (VS 2010 and .NET 4.0 Series) – ScottGu’s Blog

YES! With VS 2010 the Add Reference dialog starts on the Projects tab instead of the .NET tabs which always has taken a considerable amount of time to load, very annoying when you want to browse the filesystem for a dll file to reference.

Great improvement Scott!

Add Reference Dialog Improvements (VS 2010 and .NET 4.0 Series) - ScottGu's Blog

Filed under: .NET, ASP.NET No Comments
7Oct/071

Something fundamentally wrong with the Visual Studio IDE

As I start this posting I'm a little upset 'cause I've been working around more and more with a Java IDE "Netbeans" version 5.5.1. What I really love in Netbeans is that it can compile code with multiple version of the JDK (Java Development Kit) the equivalent of the Microsoft .NET Framework for their Visual Studio IDE.
That means if I want to write my Java application for the newest "framework/developer kit" I can switch platform inside Netbeans load my code and compile - discover what's has become deprecated - update these things, maybe add or update my methods with new possibilities. The other way around, more often used in my cases is target a framework that is older for compatibility issues.

What upsets me most is that: OK Microsoft I now you're a commercial institute but what aren't you just pushing it too far with the fact that we developers have to buy an new IDE license to be able to target a new version of a framework. Even more silly is that VS.NET 2005 can't compile to .NET 1.x though the frameworks can be installed separately and be used very seperately.

In my opinion there must be something fundamentally wrong with the Visual Studio IDE since it's framework dependent. I really feel that Microsoft is laughing their asses off saying ... "Hey dude, what to build .NET 2.0 apps" then you have to BUY VS.NET 2005" and even after that "Hey pal, Linq is cool right haha, how 'bout BUYING VS.NET 2008/Orcas".

Why not use a different IDE?

SharpDevelop announces that they have Multi-Framework Support - well it's somehow not the language or the framework itself that a barrier for making it possible - maybe it's a question about earning money .... damn again!

Filed under: .NET 1 Comment
19Dec/050

Run ASP.NET application on your Linux server

What??? - That was my first thought, - it isn't 1. of april :D Well no matter what it's awesome if this would be true and not to loose your attention now - IT IS TRUE !

The developers at dev.mainsoft.com actually made a very nice and easy deployment setup by using the Apache Tomcat application Server to host ASP.NET applications. It has it's limitations but it's definately a suitable solution setup for small applications or in terms of J2EE and .NET interop solutions. The C# guys and know build their modules, web services, API or whatever and the server admin guys deploy it on a Linux server - I can see the sun starts to shine in your eyes ....

I haven't been able to test this much but I quickly downloaded the Grasshopper packet for Windows and played around - it installed Visual Studio Extensions for "Visual MainWin C# for J2EE" and "Visual MainWin VB for J2EE" so you can build projects that can be deployed in the Tomcat application server. I build a webform and a web service into my project on the webform coded a postback event on a button that invoked my web method and printet some more on the web form and WOU WOOOOO - it worked fine.
But sure I was still in Windows, I decided to install a Tomcat on my Linux machine and then deploy the war-file there.

Let it be said, it doesn't work natively to deploy a "MainWin C# for J2EE" project on Tomcat, Tomcat needs some libraries to work with and a VmwDeployer WebApp deployed and running in Tomcat before you deploy any "MainWin C# for J2EE" projects.

I copied the Mainsoft jar libraries from my windows installation from "C:\program files\Mainsoft\Visual MainWin for J2EE\jakarta-tomcat\common\lib and pastet them into the equivalent directory of my Tomcat installation on my Linux machine.

I deployed the VmwDeployer webapp and then I deployed my own "MainWin C# for J2EE" project. An the Oscar goes to .........
It worked fine even the Web Service responded when invoked from the webform.

I must admit, -I'm impressed!

Nice work Mainsoft - I'll stay close to your website for a while :)

For more information see:
http://dev.mainsoft.com

Filed under: .NET, ASP.NET, Linux No Comments
4Apr/050

Timers with .NET and C#

I have been doing some sideworks since I started discovering the Microsoft Content Management Server 2002 which I would like to share.
I ran into a small project making a Windows application in .NET with a moderate set of features. But as I came along the design of the application I discovered som great thing to know when you doing some WinForm apps in .NET regarding threading and timers that you could benefit of when you are designing multithreaded WinForm applications with timers.First, a great part of my debugging issues was because of a namespace confusion.
In the .NET Framework 1.1 you have the 2 namespaces System.Threading and System.Timers and even inside the System.Threading namespace you have a Timer class. And the nasty part is that I discovered that you also have the a Timer class in the System.Windows.Forms namespace. Confused ???
Well the big deal is to understand the different behaviors of these classes of Timers.

  • System.Windows.Forms
    The Timer class in this namespace is for usage in Windows applications and haves as expected.
  • System.Timers
    The Timer class in this namespace is new. It is a sort of "serverbased" Timer. That means you should only use this timer when building "no GUI" applications like Console apps or Windows Services apps.
  • System.Threading
    The Timer class is also a "serverbased" Timer for "no GUI" applications.You can read about the "Server-Based" Timer @:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vbconServerBasedTimers.asp

I found out of this by using the System.Timers.Timer class in my Windows application and guess what? My GUI was stuck and nearly all the resources for my application was used by my nasty System.Timers.Timer class. Which resultet in no DataGrid updates, no statusbar updates nothing but the procedures that was handled by the my Timer.
And I even used the namespace System.Threading for my Threads ofcause and tried out the System.Threading.Timer class but nothing help me out. ARGH!

Well I went online on MSDN a couple days later and found the "Server-Based" Timer description (linked to above) and now I use the System.Windows.Forms.Timer class and "Woala" my application ran as expected with my GUI updates. My DataGrid and my StatusBar was updated when the Timer was working.

So my conclusion of this is that the System.Windows.Forms.Timer class might inherit the System.Timers.Timer class but start each Timer in a new Thread so the GUI still runs in its own seperate Thread which makes the big difference in seeing the updates of the GUI.
This is just what I assume - I havent tried to test this, but seems like a fair explanation for my problem.

That I'll be all for now - see you soon again.
Kevin Steffer

Filed under: .NET No Comments