我的任務不同IQueryable的結果是優化的一些方法,並一邊看着代碼,我發現這個瓶頸(我很抱歉,如果格式化似乎關閉):自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);
}
爲了改善它,我改變了storageCard
型形式IEnumerable<Card>
到IQueryable<Card>
(LocationPriceData
簽名也是如此)做出了巨大的改變,但現在結果也不同!
據我所知,性能改進是由於IEnumerable
和IQueryable
的實現差異而發生的,並且不同的數據是從數據庫中獲取的,但爲什麼最終結果會有所不同?
我懷疑group
部分,但因爲它比較可空int我看不到一個不同的結果的原因? Db是MS SQL服務器。
哦,在這兩種情況下的物化發生在return result.ToDictionary(x => x.ProductId, x => x.Price);
線
編輯
當改變到的IQueryable生成的查詢是不喜歡我的預期。 Cross Apply沒有任何訂購!
背後下面的代碼的邏輯從來沒有在數據庫中執行:
let price = g.OrderByDescending(t => t.Date)
.ThenByDescending(t => t.Id)
.FirstOrDefault(t => t.Price.HasValue)
這裏是生成的sql:
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
把你的問題https://codereview.stackexchange.com/ –
縱觀探查,查詢在'ToDictionary'線接收? –
@TadijaBagarić..無論如何,這似乎就是你所說的;所以無視我的意見:) – Rob