Tuesday, July 29, 2008

best perfomance in LINQ query

the performance can be drastically improved by turning off the change tracking service (context.ObjectTrackingEnabled=false) and by precompiling the queryies (CompiledQuery.Compile<>()).
Jim Wooley
http://blogs.msdn.com/alikl/archive/2007/12/18/asp-net-3-5-extensions-basic-steps-to-create-dynamic-data-web-application-focus-on-security-and-performance.aspx
http://www.codeplex.com/LINQ2SQLEB/SourceControl/ListDownloadableCommits.aspx
trouble shooting for LINQ
http://msdn2.microsoft.com/en-us/library/bb386996.aspx
\
http://blogs.msdn.com/mattwar/archive/2008/01/16/linq-building-an-iqueryable-provider-part-ix.aspx

http://blogs.msdn.com/adonet/archive/2008/03/27/ado-net-entity-framework-performance-comparison.aspx

To better understand how the query process affects performance, here’s the basic logic of a query, in order of execution.
• Parts of the query are broken up to allow for query caching to occur resulting in a query plan.
• Query is passed through to the .NET Framework data provider and executed against the database.
• The results are returned and the user iterates over the results.
• On each entity, the key properties are used to create an EntityKey.
• If the query is a tracking query then the EntityKey is used to do identity resolution.
• If the EntityKey is not found, the object is created and the properties copied into the object.
• The object is added to the ObjectStateManager for tracking.
• If merge options are used, then the properties follow the merge option rules.
• If the object is related to other objects in the ObjectContext, then the relationships between the entities are connected.

In my next post, I’ll show some of the performance improvements that can be made on the query itself and how Entity SQL and LINQ to Entities perform.
When optimizing query performance in the Entity Framework, you should consider what works best for your particular programming scenario. Here are a few key takeaways:
• Initial creation of the ObjectContext includes the cost of loading and validating the metadata.
• Initial execution of any query includes the costs of building up a query cache to enable faster execution of subsequent queries.
• Compiled LINQ queries are faster than Non-compiled LINQ queries.
• Queries executed with a NoTracking merge option work well for streaming large data objects or when changes and relationships do not need to be tracked.

Linq to SQL Deferred Loading - Lazy Load
Consider the Blog Site database I used in previous posts about Linq to SQL:

Linq to SQL Deferred Loading
If we query for the available blogs in the site using Linq to SQL, the query should look like this:
BlogDataContext ctx = new BlogDataContext(...);

var query = from b in ctx.Blogs
select b;

foreach (Blog b in query)
{
Console.WriteLine("{0}", b.BlogName);
}
This Linq query will result in the following SQL statement being sent to the DB:
SELECT [t0].[BlogID], [t0].[BlogName], [t0].[Owner]
FROM [dbo].[Blogs] AS [t0]
and the output will be:

Now, if we change the statement that outputs the name of the blog, and let it also print the number of posts in the blog:
foreach (Blog b in query)
{
Console.WriteLine("{0} has {1} posts", b.BlogName, b.Posts.Count);
}
This time, the output will be:

What Linq to SQL does is whenever it runs into the expression b.Posts.Count, it knows that the Posts collection of the blog was not yet retrieved, so it automatically generates the appropriate select statement and gets the posts. For example:
SELECT [t0].[PostID], [t0].[BlogID], [t0].[Title], [t0].[Body], [t0].[PublishDate]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[BlogID] = 'bursteg'
The problem is that a similar query is executed for each blog instance. So if we have a long list of blogs, than this simple loop can be a performance hit.
This behavior is called Linq to SQL Deferred Loading, and it is turned on by default. In order to turn it of, you can set the DeferredLoadingEnabled property to false.
BlogDataContext ctx = new BlogDataContext(...);

ctx.DeferredLoadingEnabled = false;

var query = from b in ctx.Blogs
select b;

foreach (Blog b in query)
{
Console.WriteLine("{0} has {1} posts", b.BlogName, b.Posts.Count);
}
Now, this query returns 0 as the number of posts of each blog.

No comments: