Quick Examples on LINQ To SQL Performance Tuning - Performance Profiling Your O/R Mapper

On this subject of O/R Mappers and their ability to be real chatty with your database if you are not careful, I thought I would show some quick examples with regards to LINQ To SQL and iterating against lazy loaded collection properties. For some background on why I am talking about this, see Performance Profiling O/R Mapper Calls to the Database.

 

LINQ To SQL and Northwind Database

Let's take the good 'ol Northwind Database that still refuses to die in our code examples due to freaks like me. Drop the Orders and Order_Details Tables on the LINQ To SQL Designer Surface and start developing against it in a Console Application in Visual Studio 2008.

 

LINQ To SQL

 

 

Questionable Use of Lazy-Loading

Let's grab the Orders from the Northwind Database as well as a count of the number of Order_Details for each order. The code could look like this:

 

using (NorthwindDataContext dc = new NorthwindDataContext())

{

    dc.Log = Console.Out;

 

    foreach (var order in dc.Orders.ToList())

        Console.WriteLine(string.Format("ID: {0}, Total Items:{1}",

            order.OrderID, order.Order_Details.Count));

}

 

The code looks harmless enough, but because by default the Order_Details Child Collection is lazy loaded we have a flourish of queries going back and forth between the application and the database. One query gets all the Orders, but then 1 query gets executed for each order everytime we access the Count Property of Order_Details. This is a mess for such a simple need.

 

LINQ To SQL

 

 

Eager Loading of Order_Details

We can avoid all those extra queries by eager loading the Order_Details Collection using DataLoadOptions and LoadWith

 

using (NorthwindDataContext dc = new NorthwindDataContext())

{

    var lo = new DataLoadOptions();

    lo.LoadWith<Order>(o => o.Order_Details);

    dc.LoadOptions = lo;

 

    dc.Log = Console.Out;

 

    foreach (var order in dc.Orders.ToList())

        Console.WriteLine(string.Format("ID: {0}, Total Items:{1}",

            order.OrderID, order.Order_Details.Count));

}

 

This definitely cuts down on the number of queries as we now only have 1 query total. However, we do have a lot of extra unused data moving between the application and database that we could trim.

 

LINQ To SQL

 

 

Return an Anonymous Type

Let's take the focus off our business entities a moment since it seems we may just be needing this information for reporting needs. Let's return an anonymous type from the query with just the data we need: OrderID and Order_Details.Count.

 

using (NorthwindDataContext dc = new NorthwindDataContext())

{

    dc.Log = Console.Out;

 

    var data = from o in dc.Orders

               select new

                          {

                              o.OrderID,

                              o.Order_Details.Count

                          };

 

 

    foreach (var item in data.ToList())

        Console.WriteLine(string.Format("ID: {0}, Total Items:{1}",

            item.OrderID, item.Count));

}

 

The results again is 1 query, but it returns only the data we need. This is about as clean as it can get.

 

LINQ To SQL

 

Conclusion

As you can see one needs to really look ( profile ) the communications between the O/R Mapper and the database to see what is happening behind the scenes. Again, don't go all nutty on me and create a maintenance nightmare trying to optimize every ounce of the O/R Mapper's calls, but do understand what roundtrips are occuring and data is being retrieved to verify you aren't creating a performance nightmare that can be alleviated due to a few simple adjustments as mentioned above. In this case I am just using the Logging Ability of the DataContext Class to show me the resulting queries, but you can also use SQL Server Profiler, ANTS Profiler, dotTrace, NHibernate Profiler, or whatever other tool you have at your disposal that makes sense.

 

David Hayden

 

Related Posts:

 

posted on Thursday, January 08, 2009 6:17 PM

Main

News

Green Tea

.NET Development

Enterprise Library

Patterns & Practices