My first project that used Entity Framework was a disaster. It was a web application that was so slow; you could make a cup of tea, drink it, wash up, and the home page would still be loading. Was it Entity Framework that was slow?
ŠOr was it my mistake?
As it turns out, I was making lots of small mistakes that when combined, crippled my sites performance. After making some changes, the bottleneck is no longer with Entity Framework.
Lets take a look at some of the ways you can speed up Entity Framework.
1. Keep it simple stupid (KISS)
DonӴ use the repository pattern
It seems most people are advocates of the repository pattern, and think abstracting the Entity Framework behind a repository is a great idea. Sounds good in theory, however, it makes it harder to take advantage of the powerful features of the framework.
In my experience, if you use the repository pattern with Entity Framework you will have to write more code, and you will make it so difficult to use the features, that you wonӴ even bother to use them.
Entity Framework already uses the repository pattern; so donӴ go abstracting this further unless itӳ absolutely necessary.
Entity Framework entities should be your domain entities
If youӲe using a set of entities for your domain, and a separate set for your data access layer, then thereӳ a good chance your application is slower than it should be.
Each time you copy data from view models, to domain objects, to data access objects, youӲe adding an extra step, which can slow the application to a crawl.
Make the domain objects your Entity Framework entities and cut out a step, and when possible project the data straight into view models.
2. Paging
You wouldnӴ fill a wheelbarrow to the point that its too hard to push. The same is true with database queries. If you donӴ restrict the amount of results that come back, the wheelbarrow will tip over when you try to push it.
Paging is not just about usability; itӳ essential, for increasing the speed of your application. Itӳ so important, if you only did one thing from this post to increase your performance the most, I would say it would have to be paging.
You can read about how to implement Entity Framework paging in the post titled: Entity Framework: Boost Performance with Paging
3. Projections
Sometimes you only need to display a subset of data from an entity. When this is the case, it makes no sense to load the full entity from the database. For example, when listing posts that you can edit or delete, you wouldn’t need to load the Body
field.
Projection queries allow you to select fewer fields from a database table, by projecting the data into a smaller entity.
You can find out more about projection queries in the post titled: Entity Framework Projection Queries: What are they and When Should You Use Them?
4. Be eager, not lazy
Entity Framework uses lazy loading when you have defined your relationships with the virtual
keyword. This means, the related objects will not be loaded until they’re first accessed.
Lazy loading sounds good, but it can slow down performance because there are more round trips to the database, and lazy loading can cause select N+1 issues if youӲe not careful. You can prevent lazy loading and select N+1 issues by turning off lazy loading.
5. To track, or not to track
When you know that you wonӴ be making changes to the entities youӲe retrieving, itӳ best for them not to be tracked by Entity Framework change tracking. You can do this by loading the entities with AsNoTracking
, as seen in the following example:
_context.Posts.AsNoTracking().ToList();
In most scenarios AsNoTracking
will speed up performance, especially if you are developing a web application. However, If youӲe keeping the same DbContext
hanging around for a long time, it might be better not to use AsNoTracking
.
This is because entities are cached in memory when they are first loaded, and subsequent requests are loaded from memory. Itӳ generally not recommended to leave the context hanging around for too long though, so AsNoTracking
is the recommended option.
6. Use indexes
Make sure you add indexes to your entities. For example, if you have a list of users that have an email field. You might want to make the email field unique, so that when you search for a user that has a certain email address, the database engine will load the user quicker.
You can add indexes to entities when using code-first by calling CreateIndex
in your migrations. Here is an example of adding a unique email index to a User
model.
CreateIndex(table: "dbo.Users", column: "Email", unique: true, name: "UIX_Email");
7. Reduce the amount of queries
Reduce the amount of queries by selecting all the different entities required for a single page view at the same time. For example, if you need to display a blog post and its author, you would write a query that loads data from the post and the author entities with a single query. You can do this by combining projections and eager loading related entities.
Further Reading
More detailed discussion on Entity Framework can be found in the following publications:
- Lerman, J. 2010. Programming Entity Framework. 2nd ed. O’Reilly Media.
- Lerman, J. and Miller, R. 2011. Programming Entity Framework: Code First. O’Reilly Media.
- Lerman, J. and Miller, R. 2012. Programming Entity Framework: DbContext. O’Reilly Media.