【问题标题】:How to better write this EF core 6 Group by Query如何更好地编写这个 EF core 6 Group by Query
【发布时间】:2022-12-14 03:53:38
【问题描述】:

我正在查看 EF core 6 生成的查询,我对此并不满意,因为它会产生大量阻塞开销和高效的 TSQL,我希望我是问题所在......

我的 EF 查询:

var query = db.PurchaseOrders
                .Include(i => i.Items)
                .Where(w=>w.Items.Any(a=>a.InventoryItemId==item.Id))
                .GroupBy(g=>g.SupplierId)
                .Select(s => new CurrentInventoryItemSupplier{ SupplierId=s.Key
                                , LastOrder= s.Max(m=>m.OrderDate) 
                                , FirstOrder= s.Min(m=>m.OrderDate) 
                                , Orders= s.Count() 
                }
                ).ToList();   

生成这个:

SELECT [p].[SupplierId], (
          SELECT MAX([p1].[OrderDate])
          FROM [PurchaseOrders] AS [p1]
          WHERE EXISTS (
              SELECT 1
              FROM [PurchasedItem] AS [p2]
              WHERE ([p1].[Id] = [p2].[PurchaseOrderId]) AND ([p2].[InventoryItemId] = @__item_Id_0)) AND ([p].[SupplierId] = [p1].[SupplierId])) AS [LastOrder], (
          SELECT MIN([p4].[OrderDate])
          FROM [PurchaseOrders] AS [p4]
          WHERE EXISTS (
              SELECT 1
              FROM [PurchasedItem] AS [p5]
              WHERE ([p4].[Id] = [p5].[PurchaseOrderId]) AND ([p5].[InventoryItemId] = @__item_Id_0)) AND ([p].[SupplierId] = [p4].[SupplierId])) AS [FirstOrder], (
          SELECT COUNT(*)
          FROM [PurchaseOrders] AS [p7]
          WHERE EXISTS (
              SELECT 1
              FROM [PurchasedItem] AS [p8]
              WHERE ([p7].[Id] = [p8].[PurchaseOrderId]) AND ([p8].[InventoryItemId] = @__item_Id_0)) AND ([p].[SupplierId] = [p7].[SupplierId])) AS [Orders]
      FROM [PurchaseOrders] AS [p]
      WHERE EXISTS (
          SELECT 1
          FROM [PurchasedItem] AS [p0]
          WHERE ([p].[Id] = [p0].[PurchaseOrderId]) AND ([p0].[InventoryItemId] = @__item_Id_0))
      GROUP BY [p].[SupplierId]

(计划:https://www.brentozar.com/pastetheplan/?id=rkOloR7S9

理想情况下,我希望在这里

select 
P.[SupplierId], MAX([p].[OrderDate]) as LastOrder, MIN([p].[OrderDate]) as FirtOrder, COUNT(P.Id) as Orders
FROM [PurchaseOrders] AS [p]
join [PurchasedItem] AS [p2] on [P2].[PurchaseOrderId]=[P].ID
where [p2].InventoryItemId= @__item_Id_0
group by P.[SupplierId]

(https://www.brentozar.com/pastetheplan/?id=rkOloR7S9)

有没有办法改进生成的 SQL 或制作参数化函数并从 EF 核心调用函数?

这不可能在生产数据量中存活下来

【问题讨论】:

  • 好吧,如果您需要加入 - 请加入。 Include 不是连接 - 它是加载相关实体的指令,并且在 GroupBy 之后忽略此指令。无论如何,EF Core 6 在您的案例中生成了错误的查询。看起来像回归。

标签: c# sql-server entity-framework linq query-optimization


【解决方案1】:

好的,我想通了,我必须使用 Join 方法而不是 Include

这个:

var query = db.PurchaseOrders
            .Join(db.PurchaseOrderItems, po => po.Id, pi => pi.PurchaseOrderId
            , (po, pi) => new { SupplierId = po.SupplierId, OrderDate = po.OrderDate, pi.InventoryItemId })
            .Where(w => w.InventoryItemId == item.Id)
            .GroupBy(g => g.SupplierId)
            .Select(s => new CurrentInventoryItemSupplier
            {
                SupplierId = s.Key,
                LastOrder = s.Max(m => m.OrderDate),
                FirstOrder = s.Min(m => m.OrderDate),
                Orders = s.Count(),
            });

生成

SELECT [p].[SupplierId], MAX([p].[OrderDate]) AS [LastOrder], MIN([p].[OrderDate]) AS [FirstOrder], COUNT(*) AS [Orders]
      FROM [PurchaseOrders] AS [p]
      INNER JOIN [PurchaseOrderItems] AS [p0] ON [p].[Id] = [p0].[PurchaseOrderId]
      WHERE [p0].[InventoryItemId] = @__item_Id_0
      GROUP BY [p].[SupplierId]

当你遍历它时,它没有任何问题:-)

【讨论】:

    猜你喜欢
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-07
    • 2016-09-28
    • 2015-02-17
    • 1970-01-01
    • 2013-11-20
    相关资源
    最近更新 更多