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
12Oct/093

Best Practice Visual Studio with SVN, VCS and SCM

In my research on what others have of opinions and experience with subversion (SVN) or source control management (SCM) I have collected some good links of various kind – slide shows, red book and just experiences or ideas.

My focus on my research was dealing with Web development and specially ASP.NET development with Visual Studio along with third party CMS software.

The major pain is Visual Studio, when you open up your solution and don’t touch anything your “Solution.suo” file gets modified and with SVN you have a modified state of your project folder and you need to take action either commit the change or revert the file.

My conclusion on ASP.NET development with Visual Studio is

Add the following to your ignore list:

  • Solution\Project\bin
  • Solution\Project\obj
  • Solution\Solution.suo (hidden file)

Have your repository layout like this:

  • Project
    • branches
    • tags
    • trunk

Use the trunk for your “main-line”-development. With “main-line” I think of primary development that always stable and never has checked-in code that doesn’t build.

Use your branches for creating testing, experiments and development of larger features that should not break the trunk, but needs to be committed often for backup and history of file changes. Keep your branch in sync with the trunk, remember to regularly merge changes from trunk into your branch, this prevents you from “drifting” to far away from the trunk and that makes it much easier to merge your branch back into the trunk when time comes for that.

Use your tags for creating snapshots of your trunk or branch that goes into releases and is thought of as test solutions or the LIVE beasts that hits the production servers.

If you have questions, suggestions I’d very much like to hear from you and your experience with the subject – thanks in advance.

Subversion Best Practices Links

http://www.slideshare.net/mza/subversion-best-practices
http://electricjellyfish.net/garrett/talks/oscon2004/svn-best-practices/
http://svn.collab.net/repos/svn/trunk/doc/user/svn-best-practices.html
http://www.red-bean.com/fitz/presentations/2006-06-28-AC-EU-Subversion-best-practices.pdf
http://devnulled.com/content/2006/10/guide-and-best-practices-for-subversion-branching/
http://nedbatchelder.com/text/quicksvnbranch.html
http://daptivate.com/archive/2008/08/28/subversion-best-practices-for-web-applications.aspx

Filed under: ASP.NET, CMS, Web 3 Comments
17Jan/072

SubSonic, upcoming Ruby on Rails for ASP.NET

I have been playing around with Ruby on Rails, CakePHP and found those two efforts in making it easy, simple to get on with database driven web solutions. But on my search in CodePlex i found a .NET library called SubSonic. The library is currently only really powerful in ASP.NET. They have a ClassGenerator which shortly described makes .NET classes  of all the database tables you want to have available in your .NET application as files.

The major thing in SubSonic is a build provider. It hooks on all files of the .abp extension in the App_Code folder. As soon as the files are modified you can get access to your database tables by writing your table names. When using this build povider you don't get hardcopy class files of your database tables. They are build each time a .abp file is modified.

SubSonic also comes with a Scaffold feature, but not as flexible as Ruby on Rails or CakePHP. But fair enough to get you into features for quick data creation in your development fase.

Try it out: http://www.codeplex.com/actionpack
It also has a Community: http://actionpack.wekeroad.com/

Happy coding
Kevin Steffer

Filed under: ASP.NET 2 Comments
5Feb/060

My move toward .NET 2.0

My first experience with Visual Studio 2005 Beta 2 was not so good, but since I've got my hands on the Visual Web Delveoper 2005 Express Edition and the Visual C# 2005 Express Edition I'm actualle getting more and more familiar with it.
First I think they made som minor improvements to the IDE with coding help. The Intellisense is now more intelligent when you write your lines.Another thing that I found very awesome is when you reference your own build class libraries you know get a "Update" in your context menu (right your referenced dll) in the Visual Web Developer 2005. Unfortunately th Visual C# 2005 version doesn't have that option, but it updates anyway somehow when you build again.

When it comes to new stuff in the Visual Web Developer 2005 I must admit I miss my namespace and my project DLL, it's simply gone. When you create a new webform with a "code behind" file it doesn't have the "namespace MyWebProject {}" surrounding your class - it's gone. You can make your own, but then you'd have to change all your aspx files to inherit from your page in the new namespace manually. So I think Microsoft won't recommend working with namespace declarations for your WebForms (aspx), UserControls (ascx).
But when you reference non-standard framework libraries it creates the Bin directory, but you'll only find your referenced dll files here, - weird, but it has one benefit.
You can now have C# "code behind" files along with VB.NET, C++.Net and J# "code behind" files in the same Web Project - that I think is another plus for team projects but taking all in consideration not something that benefits me working in a small business.

The Visual Web Developer 2005 has some new great features like special ASP.NET folders. You have App_LocalResources, App_GlobalResources, App_Code, App_Data, App_Theme, App_Browsers. I haven't been playing around with all of these, but the App_LocalResources has been taking under my wings. While playing around with some template web design I tried to place all my templates in the App_LocalResources and then load these files in my "code behind" files, that worked ofcause, but when you try to access these template files (they are simple xml files) from your client browser you get an 404 File Not Found error, that I think is pretty nice for a guy like me who also made my mistakes by place VBScript kode in .inc files in my early days of ASP programming. Well what I found out after the project was done was that if anyone guessed a .inc file name on the server the source code was printed to him - BAHHH and in worst case the datasource connection string with username AND password would be visible to him.
If you should happen to have made such a project I think we found a great solution without renaming and edit all your include statements. Simply add a .inc files to be executed by asp.dll in your IIS 5.0 Application configuration, and the files execute instead of being displayed as is.

One thing I also miss is the GridLayout for WebForms it's extremely fast to create some ok looking prototype stuff with the GridLayout - you don't have to setup your layout with tables or div's and the style the placing which often takes considerably a lot of time, and that's not spend well while prototyping.

Well I guess that will be all for know.
I might come back with some other new features of the .NET 2.0 in a while that are bugging or thrilling me.

Untill then - Happy Coding
Kevin Steffer

Filed under: ASP.NET No Comments