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

186 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 视图逻辑修复方案总结
## 📌 问题回顾
用户反馈数据库视图查询结果大部分为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片段**
```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` 条件进行关联:
```sql
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语句
- 便于调试和验证
### 存储过程核心逻辑
```sql
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. 调用 API`GET /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%为红色
## ✅ 完成检查清单
- [x] 分析根本原因
- [x] 设计解决方案
- [x] 编写存储过程SQL
- [x] 修改应用层代码
- [x] 准备执行说明文档
- [ ] **用户执行**在数据库中创建存储过程
- [ ] **测试**验证存储过程返回正确数据
- [ ] **集成**前端调用验证
- [ ] **性能**确认查询时间<1秒