Blog
Common EF Core mistake: not using the difference between Tracking and No-Tracking Queries
What is this?
By default, a query is trackable, it means that if your query changes some properties of some entities and saves them, theses modifications will be repercuted on the database.
You query a product, you change his name and save the changes. The next time you will query this product his name will be the updated one. Great.
What is AsNoTracking?
The AsNoTracking method allows a query to not be trackable, so no changes will ever happen in the database, even if you call the SaveChanges method.
There is absolutely no sense in our previous example but what if you already know that your query won't modify the database?
What happens behind the scene?
Take this query:
return
myDbContext.Products
.Where(x=>x.CategoryId == 1)
.ToList()
EF Core will generate the query, send the query to the database provider that will run it then returns the results to EF Core that will parse and map the data, then EF Core will add the tracking fields it needs to work (basically it will add another field for all the entities fields to track the change, and some more for stuff like the indexes) then it will pass the results to your code than can continues to run.
What is the problem? Well, it hasn't but the step that consist for EF Core to add the tracking fields is a big one and can use massive memory space if it processes a lot of data, why doing this if you already know when you send the query that you won't update the database?
Let's see what happens if we now add the AsNoTracking to our query.
The query now looks like this:
return
myDbContext.Products
.AsNoTracking()
.Where(x=>x.CategoryId == 1)
.ToList()
What happens now behind the scene? Exaclty the same that for the first query except that the tracking step is skipped:
Is there any difference for your code? There is absolutely no difference for your code except that the SaveChanges method won't have any effect now if your are using it, if you don't there is no difference for you.
Why caring about this?
What are the gains? Performance!
Non-tracked queries can run 7 or 8 times faster and use 4 or 5 less memories. If your queries manipulate a lot of data, that can be a massive gain.
Note two things:
- the first thing is that the gain will be on the .NET part, no gain will be on the database part. It's logic because we saw that the query that is sends to the SQL database provider is exactly the same when your are using AsNoTracking or not, this is the EF Core part that is impacted.
- the second thing to know and that's very important is that the gain will depends a lot of the database provider you use. The numbers in this post are accurrate for SQL server and the majority of the SQL database providers but Nick Chapsas has demontrated that the AsNoTracking method has barely no effect if you are using SQLite for example. You have to check the SQL provider you are using to know if theses kind of optimizations will have an impact on your performance or not.