Ma tâche est d'optimiser certaines méthodes et en regardant le code que je trouve ce goulot d'étranglement (Pardonnez-moi si le formatage semble désactivé):résultat IQueryable différent de IEnumerable
// ...
IEnumerable<Card> storageCards =
Db.StorageCards
.Where(x => x.Active && x.DocumentType == (int)DocumentType.Import);
// excludeLastDate is bool
storageCards = storageCards.Where(x => (excludeLastDate && x.Date < toD)
|| (!excludeLastDate && x.Date <= toD));
return LocationPriceData(storageCards, locationId.Value);
}
private Dictionary<int, decimal> LocationPriceData(IEnumerable<Card> storageCards
, int locationId)
{
// sc.LocationId, sc.ProductId are nullable int
// sc.Price is nullable decimal
// sc.Date is datetime, not null
var result = from sc in storageCards
where sc.LocationId == locationId
group sc by sc.ProductId
into g
let price = g.OrderByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
.FirstOrDefault(t => t.Price.HasValue)
where price != null
select new
{
ProductId = g.Key.Value,
Price = price.LevelInputPrice.Value
};
return result.ToDictionary(x => x.ProductId, x => x.Price);
}
Pour l'améliorer, je changé sous forme de type storageCard
IEnumerable<Card>
à IQueryable<Card>
(en LocationPriceData
signature ainsi) qui a fait une énorme différence, mais maintenant les résultats sont différents aussi! Je comprends que l'amélioration des performances s'est produite en raison de la différence d'implémentation IEnumerable
et IQueryable
et que différentes données sont extraites de la base de données, mais pourquoi le résultat final est-il différent?
Je suspecte la partie group
mais comme il compare un int nullable je ne peux pas voir une raison pour le résultat différent? Db est le serveur MS SQL.
Oh, et dans les deux cas, la matérialisation arrive à la ligne return result.ToDictionary(x => x.ProductId, x => x.Price);
EDIT
Lors de la modification de la requête IQueryable généré est pas comme ce que je pensais. Le Cross Application n'a aucune commande dedans!
La logique derrière le code suivant est jamais exécuté sur DB:
let price = g.OrderByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
.FirstOrDefault(t => t.Price.HasValue)
Voici le SQL généré:
exec sp_executesql N'SELECT
[Element1].[Id] AS [Id],
[Project2].[ProductId] AS [ProductId],
[Element1].[LevelInputPrice] AS [LevelInputPrice]
FROM (SELECT
[Distinct1].[ProductId] AS [ProductId]
FROM (SELECT DISTINCT
[Extent1].[ProductId] AS [ProductId]
FROM [dbo].[StorageCard] AS [Extent1]
WHERE ((([Extent1].[Active] = 1) AND (10 = [Extent1].[DocumentType])) OR (40 = [Extent1].[DocumentType]) OR ((70 = [Extent1].[DocumentType]) AND ([Extent1].[InputQuantity] > cast(0 as decimal(18))))) AND (((@p__linq__0 = 1) AND ([Extent1].[Date] < @p__linq__1)) OR ((@p__linq__2 <> cast(1 as bit)) AND ([Extent1].[Date] <= @p__linq__3))) AND ([Extent1].[LocationId] = @p__linq__4)
) AS [Distinct1]) AS [Project2]
CROSS APPLY (SELECT TOP (1)
[Extent2].[Id] AS [Id],
[Extent2].[Date] AS [Date],
[Extent2].[DocumentType] AS [DocumentType],
[Extent2].[InputQuantity] AS [InputQuantity],
[Extent2].[LevelInputPrice] AS [LevelInputPrice],
[Extent2].[Active] AS [Active],
[Extent2].[LocationId] AS [LocationId],
[Extent2].[ProductId] AS [ProductId]
FROM [dbo].[StorageCard] AS [Extent2]
WHERE ((([Extent2].[Active] = 1) AND (10 = [Extent2].[DocumentType])) OR (40 = [Extent2].[DocumentType]) OR ((70 = [Extent2].[DocumentType]) AND ([Extent2].[InputQuantity] > cast(0 as decimal(18))))) AND (((@p__linq__0 = 1) AND ([Extent2].[Date] < @p__linq__1)) OR ((@p__linq__2 <> cast(1 as bit)) AND ([Extent2].[Date] <= @p__linq__3))) AND ([Extent2].[LocationId] = @p__linq__4) AND (([Project2].[ProductId] = [Extent2].[ProductId]) OR (([Project2].[ProductId] IS NULL) AND ([Extent2].[ProductId] IS NULL))) AND ([Extent2].[LevelInputPrice] IS NOT NULL)) AS [Element1]
WHERE [Element1].[Id] IS NOT NULL',N'@p__linq__0 bit,@p__linq__1 datetime2(7),@p__linq__2 bit,@p__linq__3 datetime2(7),@p__linq__4 int',@p__linq__0=0,@p__linq__1='2017-07-19 08:43:52.6901840',@p__linq__2=0,@p__linq__3='2017-07-19 08:43:52.6901840',@p__linq__4=11
Prenez votre question https://codereview.stackexchange.com/ –
En regardant le profileur, une requête est reçue à la ligne 'de ToDictionary'? –
@ TadijaBagarić ..Quel .. semble être ce que vous disiez de toute façon; donc ne pas tenir compte de mes commentaires :) – Rob