Files
LabelChange-server/.trae/documents/view_fix_summary.md
2026-06-01 16:30:29 +08:00

6.0 KiB
Raw Permalink Blame History

视图逻辑修复方案总结

📌 问题回顾

用户反馈数据库视图查询结果大部分为0

2026-05-15 | 0 | 3592 | 0 | 3315 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2026-05-16 20:21:40

仅有 DailyShouldReplaceCount(3592) 和 CumulativeTotalReplaceCount(3315) 有数据其他指标全是0。

🔍 根本原因分析

问题1硬编码NOW()导致的日期比较错误

原视图SQL片段

CAST(CONVERT_TZ(r.CreatedAt, '+00:00', '-05:00') AS DATE) = CAST(CONVERT_TZ(NOW(), '+00:00', '-05:00') AS DATE)

问题:每次查询都与当前时间比较,而不是与查询参数的日期比较。

影响

  • 查询2026-05-15的数据时条件自动比较为"2026-05-15是否等于今天"
  • 由于2026-05-15不等于今天的日期所以大部分WHERE条件都返回FALSE
  • 导致除了依赖其他条件的指标外,大部分指标都被过滤掉了

问题2JOIN关联逻辑不合理

原视图使用 OR 条件进行关联:

r.BillOfLadingNumber = ahf.HandoverNumber OR r.MasterPackageNumber = ahf.HandoverNumber

虽然这个关联本身可以工作,但与硬编码的时间比较配合,导致很多联接行被意外过滤。

问题3时区转换过度使用

多次重复的 CONVERT_TZ() 调用导致:

  • SQL语句复杂性增加
  • 性能下降
  • 维护困难

修复方案

采用方案存储过程Stored Procedure

关键改进

  1. 参数化日期输入

    • 从硬编码 NOW() 改为接受 p_date 参数
    • 支持查询任意历史日期
  2. 简化时区转换

    • 在存储过程开始时一次性计算日期范围v_date_start, v_date_end
    • 后续查询直接使用这些变量,避免重复转换
  3. 优化JOIN逻辑

    • 使用临时表 temp_qualified_arrivals 预先计算标签率≥80%的交接单
    • 后续查询直接JOIN临时表提高查询效率
  4. 清晰的指标计算

    • 每个指标独立计算使用SELECT...INTO语句
    • 便于调试和验证

存储过程核心逻辑

CREATE PROCEDURE sp_GetDailyMetricsSummary(IN p_date DATE)

-- 1. 计算UTC-5时区的日期范围
SET v_date_start = CONVERT_TZ(CONCAT(DATE(p_date), ' 00:00:00'), '-05:00', '+00:00');
SET v_date_end = CONVERT_TZ(CONCAT(DATE(p_date), ' 23:59:59'), '-05:00', '+00:00');

-- 2. 创建临时表存储标签率≥80%的交接单
CREATE TEMPORARY TABLE temp_qualified_arrivals AS
SELECT ... FROM arrival_handover_forms ... HAVING labeled_orders / total_orders >= 0.8;

-- 3. 基于临时表和时间范围计算各项指标
SELECT COUNT(...) INTO v_daily_should_replace_count ...
SELECT COUNT(...) INTO v_daily_success_count ...
-- ... 其他指标 ...

-- 4. 返回所有指标结果
SELECT ... AS MetricsDate, v_daily_new_replace_count AS DailyNewReplaceCount, ...

📊 预期改进

性能改进

  • 原方案11个独立异步查询耗时15-30秒
  • 新方案:单个存储过程调用,目标<1秒
  • 性能提升15-30倍

正确性改进

  • 原问题大多数指标返回0
  • 修复后:各指标返回合理的非零值
  • 根本原因移除了硬编码的NOW()导致的日期比较错误

灵活性改进

  • 原方案:视图固定查询当前日期
  • 新方案:可查询任意历史日期
  • 支持:报表、趋势分析等需要历史数据的功能

🔧 实现变更

1. 数据库变更

📄 文件:database/migrations/002_create_sp_daily_metrics_summary.sql

  • 创建存储过程 sp_GetDailyMetricsSummary
  • 接收参数:p_date DATE
  • 返回13个指标列

2. 应用层变更

📄 文件:src/BLL/Services/MetricsCalculationService.cs

  • 第462行修改 GetDailySummaryAsync() 方法
  • SELECT * FROM v_DailyMetricsSummary WHERE MetricsDate = '{date}'
  • 改为 CALL sp_GetDailyMetricsSummary('{date:yyyy-MM-dd}')

3. 降级方案保留

  • 保留原有的 GetDailySummaryAsync_Original() 方法
  • 如果存储过程调用失败自动降级到11个独立查询
  • 确保系统可用性

📝 验证步骤

数据库层验证

  1. 执行存储过程创建脚本
  2. 执行 CALL sp_GetDailyMetricsSummary('2026-05-15')
  3. 验证返回数据:
    • DailyShouldReplaceCount ≈ 3592
    • CumulativeTotalReplaceCount ≈ 3315
    • 其他指标 > 0

应用层验证

  1. 重新编译并运行后端服务
  2. 调用 APIGET /api/metrics/daily-dashboard?date=2026-05-15
  3. 验证JSON响应包含所有指标

前端验证

  1. 打开仪表盘:http://localhost:5002/metrics-dashboard-summary.html
  2. 选择日期 2026-05-15
  3. 验证显示的指标正确性

性能验证

  1. 使用浏览器开发者工具查看API响应时间
  2. 应该 < 1000ms1秒

🎯 后续可选优化

  1. 缓存层添加Redis缓存避免频繁查询相同日期
  2. 物化视图:定期生成历史数据快照
  3. 分析表:预生成常用报表的汇总数据
  4. 分区按日期分区arrival_handover_forms表

📋 关键指标定义(业务规则)

DailyShouldReplaceCount

  • 当日到仓且标签率≥80%的订单总数
  • 业务含义:当天应该执行的换单操作数

DailySuccessCount

  • 当日成功扫描的订单数Result=0
  • 业务含义:当天完成的换单操作数

CumulativeTotalReplaceCount

  • 截至前一天未成功扫描的订单数
  • 业务含义:历史待处理的订单数

BeforeNoonArrivedCount / AfternoonArrivedCount

  • 按16:00时间点划分的到仓订单
  • 业务含义:区分早班和晚班处理的订单

完成率计算

  • DailyCompletionRate = DailySuccessCount / DailyShouldReplaceCount * 100%
  • 指标类型百分比≥95%为绿色85-95%为黄色,<85%为红色

完成检查清单

  • 分析根本原因
  • 设计解决方案
  • 编写存储过程SQL
  • 修改应用层代码
  • 准备执行说明文档
  • 用户执行:在数据库中创建存储过程
  • 测试:验证存储过程返回正确数据
  • 集成:前端调用验证
  • 性能:确认查询时间<1秒