diff --git a/lastleg-service/src/main/java/com/baiyue/lastleg/selfoperated/analytics/query/AnalyticsReadSql.java b/lastleg-service/src/main/java/com/baiyue/lastleg/selfoperated/analytics/query/AnalyticsReadSql.java index 4599fa82e..51129fc4b 100644 --- a/lastleg-service/src/main/java/com/baiyue/lastleg/selfoperated/analytics/query/AnalyticsReadSql.java +++ b/lastleg-service/src/main/java/com/baiyue/lastleg/selfoperated/analytics/query/AnalyticsReadSql.java @@ -33,7 +33,10 @@ public final class AnalyticsReadSql { String localEvidence="CONVERT_TZ(evidence_at_utc,'+00:00','+08:00')"; String observedStart="CONVERT_TZ(GREATEST(evidence_at_utc,#{p.coveredFrom}),'+00:00','+08:00')"; String observedEnd="CONVERT_TZ(#{p.coveredUntil},'+00:00','+08:00')"; - String sql=candidates("SUMMARY".equals(kind))+" bounds AS (SELECT evidence.*," + // Candidate identity is already unique. DISTINCT preserves that identity while + // preventing MySQL from merging these per-SKU date calculations into every fact row. + String boundaryProjection="SUMMARY".equals(kind)?"SELECT DISTINCT evidence.*,":"SELECT evidence.*,"; + String sql=candidates("SUMMARY".equals(kind))+" bounds AS ("+boundaryProjection +"CASE WHEN evidence_at_utc IS NOT NULL AND #{p.completeFrom} IS NOT NULL AND #{p.completeUntil} IS NOT NULL THEN " +"GREATEST(#{p.from},#{p.completeFrom},TIMESTAMPADD(DAY,CASE WHEN CAST("+localEvidence+" AS TIME)='00:00:00' THEN 0 ELSE 1 END,DATE("+localEvidence+"))) END full_start," +"LEAST(#{p.until},#{p.completeUntil},#{p.anchor}) full_end," @@ -84,6 +87,26 @@ public final class AnalyticsReadSql { +"FROM counted c LEFT JOIN ll_selfop_inventory_snapshot st ON st.snapshot_run_id=#{p.inventoryRun} AND st.source_account=#{p.account} " +"AND st.warehouse_code=#{p.warehouse} AND st.customer_code=c.customer_code AND st.sku_code=c.sku_code AND st.product_quality=0) "; if("SUMMARY".equals(kind)){ + // Aggregate facts before joining SKU evidence. Repeating boundary expressions + // inside every fact's SUM dominated the long-window MySQL execution profile. + int rangeStart=sql.indexOf(" ranged AS (");int rangeEnd=sql.indexOf(" metric_sales AS (",rangeStart); + sql=sql.substring(0,rangeStart)+" ranged AS (SELECT d.customer_code,d.sku_code,SUM(d.outbound_quantity) observed_sum," + +"COUNT(*) actual_days,SUM(d.outbound_order_count) order_sum,MIN(d.quantity_unit) min_unit,MAX(d.quantity_unit) max_unit," + +"SUM(CASE WHEN d.business_date>=#{p.completeFrom} AND d.business_date<#{p.completeUntil} AND d.business_date<#{p.anchor} THEN 1 ELSE 0 END) actual_complete " + +"FROM ll_selfop_sku_daily_sales d WHERE d.sales_run_id=#{p.salesRun} AND"+KEY_FILTER + +" AND d.business_date>=#{p.from} AND d.business_date<#{p.until} GROUP BY d.customer_code,d.sku_code),"+sql.substring(rangeEnd); + String scopedCount="SELECT COUNT(*) FROM ll_selfop_sku_daily_sales d2 WHERE d2.sales_run_id=#{p.salesRun} " + +"AND d2.source_account=#{p.account} AND d2.warehouse_code=#{p.warehouse} " + +"AND d2.customer_code=b.customer_code AND d2.sku_code=b.sku_code "; + String fullSpan="CASE WHEN r.actual_days IS NULL THEN 0 " + +"WHEN b.full_start<=GREATEST(#{p.from},#{p.completeFrom}) AND b.full_end>=LEAST(#{p.until},#{p.completeUntil},#{p.anchor}) " + +"THEN r.actual_complete ELSE ("+scopedCount+"AND d2.business_date>=GREATEST(#{p.from},b.full_start) " + +"AND d2.business_date=#{p.until} THEN r.actual_days ELSE ("+scopedCount + +"AND d2.business_date>=GREATEST(#{p.from},b.observed_start) AND d2.business_date=CAST(? AS DATE) AND d.business_date=DATE_SUB")); + assertTrue(page.contains("GROUP BY d.customer_code,d.sku_code")); assertFalse(page.contains("business_date>=DATE_SUB")); assertFalse(page.contains("ll_selfop_inventory_snapshot")); assertFalse(page.contains("metric_sales"));assertFalse(page.contains("FROM bounds WHERE 1=0")); + assertTrue(page.contains("bounds AS (SELECT DISTINCT evidence.*,")); assertTrue(page.endsWith("ORDER BY observed_quantity IS NULL,observed_quantity DESC,sku_code ASC,customer_code ASC LIMIT ? OFFSET ?")); - assertTrue(page.indexOf("GROUP BY b.customer_code,b.sku_code")