Topics covered:
- SQL Profilers
- The N+1 Query Problem
- Incorrect Use of ToList()
- Incorrect use of SELECT *
- Deleting objects faster with native SQL
Video (in Bulgarian)
Presentation contents:
What is SQL Profiler
SQL Profilersintercept the SQL queries executed at the server side- Powerful tools to diagnose the hidden Entity Framework queries
- SQL Server has “SQL Server Profiler” tool
- Part of Enterprise / Developer edition (paid tool)
- A free SQL Profiler exists for SQL Server:
- Express Profiler: http://expressprofiler.codeplex.com
- Easy-to-use, open-source, lightweight, powerful, … and works!
The N+1 Query Problem
- What is the N+1 Query Problem?
- Imagine a database that contains tables Products, Suppliers and Categories
- Each product has a supplier and a category
- We want to print each Product along with its Supplier and Category:
- Imagine a database that contains tables Products, Suppliers and Categories
foreach (var product in context.Products)
{
Console.WriteLine("Product: {0}; {1}; {2}",
product.ProductName, product.Supplier.CompanyName,
product.Category.CategoryName);
}
- This code will execute N+1 SQL queries:
foreach (var product in context.Products)
{
Console.WriteLine("Product: {0}; {1}; {2}",
product.ProductName, product.Supplier.CompanyName,
product.Category.CategoryName);
}
One query to retrive the products
Additional N queries to retrieve the category for each product
Additional N queries to retrieve the supplier for each product
- Imagine we have 100 products in the database
- That’s ~ 201 SQL queries ->
very slow! - We could do the same with a single SQL query
- That’s ~ 201 SQL queries ->
Solution to the N+1 Query Problem
- Fortunately there is an easy way in EF to avoid the N+1 query problem:
foreach (var product in context.Products.
Include("Supplier").Include("Category"))
{
Console.WriteLine("Product: {0}; {1}; {2}",
product.ProductName, product.Supplier.CompanyName,
product.Category.CategoryName);
}
Using
Include(…) method only one SQL query with join is made to get the related entitiesNo additional SQL queries are made here for the related entities
Incorrect Use of ToList
- In EF invoking
ToList()executes the underlying SQL query in the database- Transforms
IQueryabletoList - Invoke
ToList()as late as possible, after all filtering, joins and groupings
- Transforms
- Avoid such code:
- This will cause all order details to come from the database and to be filtered later in the memory
List orderItemsFromTokyo =
northwindEntities.Order_Details.ToList().
Where(od => od.Product.Supplier.City == "Tokyo").ToList();
Deleting Entities
- Deleting entities (slower):
- Executes
SELECT+DELETEcommands
- Executes
NorthwindEntities northwindEntities = new NorthwindEntities();
var category = northwindEntities.Categories.Find(46);
northwindEntities.Categories.Remove(category);
northwindEntities.SaveChanges();
- Deleting entities with native SQL (faster):
- Executes a single
DELETEcommand
- Executes a single
NorthwindEntities northwindEntities = new NorthwindEntities();
northwindEntities.Database.ExecuteSqlCommand(
"DELETE FROM Categories WHERE CategoryID = {0}", 46);