Optimiser une requête LINQ : pas toujours une bonne idée
J'ai voulu optimiser requête LINQ suivante :
var q2 = from c in context.Categories
select new
{
c.CategoryName,
SupplierContactName = (from s in context.Suppliers
let ProductCount = (from p in s.Products
where p.CategoryID == c.CategoryID
select p).Count()
orderby ProductCount descending
select new { s.ContactName, ProductCount }).First()
};
J'ai préféré utiliser la surcharge de Count qui inclue le where :
var q3 = from c in context.Categories
select new
{
c.CategoryName,
SupplierContactName = (from s in context.Suppliers
let ProductCount = s.Products.Count(p => p.CategoryID == c.CategoryID)
orderby ProductCount descending
select new { s.ContactName, ProductCount }).First()
};
Cette optimisation est valable pour LINQ To Object.
Cependant, ce n'est pas une si bonne idée que ça dans le cas de LINQ To SQL
En effet, la première requête va générer les requête SQL suivantes :
SELECT [t0].[CategoryName], [t0].[CategoryID]
FROM dbo.Categories AS [t0]
SELECT TOP (1) [t2].[ContactName], [t2].[value] AS [ProductCount]
FROM (
SELECT [t0].[ContactName], (
SELECT COUNT(*)
FROM [dbo].[Products] AS [t1]
WHERE ([t1].[CategoryID] = (@x1)) AND ([t1].[SupplierID] = [t0].[SupplierID])
) AS [value]
FROM [dbo].[Suppliers] AS [t0]
) AS [t2]
ORDER BY [t2].[value] DESC
-- @x1: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
cette dernière étant répété pour chaque catégorie.
Pour ma requête LINQ optimisée, les requêtes SQL générées seront les suivantes :
SELECT [t0].[CategoryName], [t0].[CategoryID]
FROM dbo.Categories AS [t0]
SELECT TOP (1) [t3].[ContactName], [t3].[value] AS [ProductCount]
FROM (
SELECT [t0].[ContactName], (
SELECT COUNT(*)
FROM (
SELECT
(CASE
WHEN [t1].[CategoryID] = (@x1) THEN 1
WHEN NOT ([t1].[CategoryID] = (@x1)) THEN 0
ELSE NULL
END) AS [value], [t1].[SupplierID]
FROM [dbo].[Products] AS [t1]
) AS [t2]
WHERE ([t2].[value] = 1) AND ([t2].[SupplierID] = [t0].[SupplierID])
) AS [value]
FROM [dbo].[Suppliers] AS [t0]
) AS [t3]
ORDER BY [t3].[value] DESC
-- @x1: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
Comme quoi, optimiser une requête LINQ To SQL peut dégrader les performances de votre application. 
Ce qu'il faut savoir c'est que LINQ To SQL utilise un Expression Tree (c'est le principe des IQueryable<T>) afin de convertir la requête LINQ en requête SQL. Pendant la conversion, on a une passe d'optimisation de la requête.
Pour conclure, pour les requêtes LINQ To SQL, essayez d'être le plus basique possible afin que l'expression tree généré par votre LINQ requête puisse être facilement traduisible et optimisé en SQL.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :