From 6a7806ff0833c33c08a8f686ba42dd56edc0487c Mon Sep 17 00:00:00 2001 From: nns Date: Fri, 9 Oct 2026 21:27:37 +0500 Subject: [PATCH] =?UTF-8?q?perf(movements):=20=D1=81=D1=87=D0=B8=D1=82?= =?UTF-8?q?=D0=B0=D1=82=D1=8C=20total=20=D0=BF=D0=BE=20=D0=B1=D0=B0=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=B9=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86?= =?UTF-8?q?=D0=B5=20=D0=B1=D0=B5=D0=B7=20join=20(287k=20=D0=B4=D0=B2=D0=B8?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D0=B9:=20count=201.1=D1=81=E2=86=9265?= =?UTF-8?q?=D0=BC=D1=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit На реальном объёме перенесённого магазина список движений отдавал >2.5с из-за COUNT по 3-table join. Count теперь по stock_movements с фильтрами (join не меняет число строк). Co-Authored-By: Claude Opus 5.5 --- .../Controllers/Inventory/StockController.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) 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 {