diff --git a/src/food-market.api/Controllers/Inventory/StockController.cs b/src/food-market.api/Controllers/Inventory/StockController.cs index 356b833..87b4972 100644 --- a/src/food-market.api/Controllers/Inventory/StockController.cs +++ b/src/food-market.api/Controllers/Inventory/StockController.cs @@ -239,6 +239,16 @@ public record MovementRow( [FromQuery] string? order = null, CancellationToken ct = default) { + // COUNT считаем по одной таблице (без join на products/stores) — на больших объёмах + // (сотни тысяч движений) count по 3-way join был узким местом (~1.1с vs ~65мс). + // Join не меняет число строк: у каждого движения ровно один товар и один склад. + var countQ = _db.StockMovements.AsQueryable(); + if (storeId.HasValue) countQ = countQ.Where(m => m.StoreId == storeId.Value); + if (productId.HasValue) countQ = countQ.Where(m => m.ProductId == productId.Value); + if (from.HasValue) countQ = countQ.Where(m => m.OccurredAt >= from.Value); + if (to.HasValue) countQ = countQ.Where(m => m.OccurredAt < to.Value); + var total = await countQ.CountAsync(ct); + var q = from m in _db.StockMovements join p in _db.Products on m.ProductId equals p.Id join st in _db.Stores on m.StoreId equals st.Id @@ -248,8 +258,6 @@ public record MovementRow( if (productId.HasValue) q = q.Where(x => x.m.ProductId == productId.Value); if (from.HasValue) q = q.Where(x => x.m.OccurredAt >= from.Value); if (to.HasValue) q = q.Where(x => x.m.OccurredAt < to.Value); - - var total = await q.CountAsync(ct); var desc = string.Equals(order, "desc", StringComparison.OrdinalIgnoreCase); q = (sort, desc) switch {