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, these modifications will be reflected in the database.
You query a product, you change its name and save the changes. The next time you query this product its 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.
That makes 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 scenes?
Take this query:
return
myDbContext.Products
.Where(x=>x.CategoryId == 1)
.ToList()
EF Core will generate the query, send it to the database provider that will run it then return the results to EF Core, which 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 every entity field to track the change, and some more for stuff like the indexes), then it will pass the results to your code, which can continue to run.
What is the problem? Well, there isn't one, but the step where EF Core adds the tracking fields is a big one and can use a massive amount of memory if it processes a lot of data. Why do 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 scenes? Exactly the same as 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 you are using it; if you don't, there is no difference for you.
Why care about this?
What are the gains? Performance!
Non-tracked queries can run 7 or 8 times faster and use 4 or 5 times less memory. 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 side, there will be no gain on the database side. It's logical because we saw that the query that is sent to the SQL database provider is exactly the same whether you are using AsNoTracking or not; it is the EF Core part that is impacted.
- the second thing to know, and it's very important, is that the gain will depend a lot on the database provider you use. The numbers in this post are accurate for SQL Server and the majority of the SQL database providers, but Nick Chapsas has demonstrated that the AsNoTracking method has almost no effect if you are using SQLite for example. You have to check the SQL provider you are using to know whether these kinds of optimizations will have an impact on your performance or not.