From 25012c30f4c30f403e69cd22d4ce691e27e0d78d Mon Sep 17 00:00:00 2001 From: yml2213 Date: Mon, 26 Oct 2026 16:04:52 +0800 Subject: [PATCH] =?UTF-8?q?perf(cost-center):=20=E5=95=86=E5=93=81?= =?UTF-8?q?=E9=A1=B5=E8=B7=B3=E8=BF=87=E6=97=A0=E5=85=B3=20affiliate=20?= =?UTF-8?q?=E8=81=9A=E5=90=88=E5=B9=B6=E8=A1=A5=E9=83=A8=E5=88=86=E7=B4=A2?= =?UTF-8?q?=E5=BC=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../113_cost_center_query_indexes.sql | 19 +++++++++++++++++++ .../cost-center/product-catalog-service.ts | 13 ++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 apps/backend/src/db/migrations/113_cost_center_query_indexes.sql diff --git a/apps/backend/src/db/migrations/113_cost_center_query_indexes.sql b/apps/backend/src/db/migrations/113_cost_center_query_indexes.sql new file mode 100644 index 00000000..ed5bf6d1 --- /dev/null +++ b/apps/backend/src/db/migrations/113_cost_center_query_indexes.sql @@ -0,0 +1,19 @@ +-- 113_cost_center_query_indexes.sql +-- 成本中心商品页性能:总览的「未映射订单项」与商品列表的 affiliate 任务聚合。 +-- +-- 背景:测试库 40 万 order_items 时,总览对 canonical_product_id IS NULL 做全表扫描约 3.8s; +-- 商品列表在人工 Tab 仍会聚合 30 天 affiliate 任务,测试机 IO 差时超过 10s。 +-- 两个索引都是部分索引,体积远小于全表索引。 + +CREATE INDEX IF NOT EXISTS idx_order_items_unmapped_mode + ON order_items (fulfillment_mode) + WHERE canonical_product_id IS NULL; + +CREATE INDEX IF NOT EXISTS idx_fulfillment_tasks_affiliate_recent + ON fulfillment_tasks (created_at) + WHERE executor_key = 'affiliate_dash'; + +COMMENT ON INDEX idx_order_items_unmapped_mode IS + '成本中心总览:按履约方式统计未归一订单项,避免全表扫 order_items'; +COMMENT ON INDEX idx_fulfillment_tasks_affiliate_recent IS + '自动发货任务 30 天聚合:只索引 affiliate_dash,减少商品列表聚合扫描'; diff --git a/apps/backend/src/services/cost-center/product-catalog-service.ts b/apps/backend/src/services/cost-center/product-catalog-service.ts index e9da9556..cf9f8f90 100644 --- a/apps/backend/src/services/cost-center/product-catalog-service.ts +++ b/apps/backend/src/services/cost-center/product-catalog-service.ts @@ -106,6 +106,14 @@ export async function listAdminProducts(payload: JsonObject = {}) { baseClauses.push(productSourceFilterSql(baseParams.length)) } + // 人工/接单平台商品不需要 affiliate 任务统计:跳过 30 天 fulfillment_tasks 聚合。 + // 只有「全部」和「自动发货」Tab 才需要这条聚合,避免小库 IO 被无关数据拖慢。 + const needsAffiliateTaskStats = !source || source === 'affiliate_dash' + const affiliateTaskJoinSql = needsAffiliateTaskStats ? AFFILIATE_TASK_AGG_JOIN : '' + const affiliateColumnsSql = needsAffiliateTaskStats + ? 'COALESCE(aff.task_count, 0) AS affiliate_task_count, aff.last_fulfilled_at AS affiliate_last_fulfilled_at' + : '0::int AS affiliate_task_count, NULL::timestamptz AS affiliate_last_fulfilled_at' + const categoryId = normalizeCategoryFilter(payload.categoryId ?? payload.category_id) const rootCategoryId = normalizeCategoryFilter(payload.rootCategoryId ?? payload.root_category_id) const listParams = [...baseParams] @@ -196,11 +204,10 @@ export async function listAdminProducts(payload: JsonObject = {}) { LIMIT 1 ) ) AS active_cost_effective_from, - COALESCE(aff.task_count, 0) AS affiliate_task_count, - aff.last_fulfilled_at AS affiliate_last_fulfilled_at + ${affiliateColumnsSql} FROM product_catalog p ${PRODUCT_CATEGORY_JOINS} - ${AFFILIATE_TASK_AGG_JOIN} + ${affiliateTaskJoinSql} ${where} ORDER BY p.status ASC,