上传源代码版本
This commit is contained in:
293
.trae/docs/ParseDurationMs_Field_Addition.md
Normal file
293
.trae/docs/ParseDurationMs_Field_Addition.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# ParseDurationMs 字段添加总结
|
||||
|
||||
**日期**: 2026-05-13
|
||||
**状态**: ✅ 完成并编译通过
|
||||
|
||||
---
|
||||
|
||||
## 📋 字段定义
|
||||
|
||||
### 字段信息
|
||||
- **字段名**: `ParseDurationMs`
|
||||
- **数据类型**: `INT`
|
||||
- **可空**: 是(DEFAULT NULL)
|
||||
- **含义**: PDF解析花费的时间(毫秒)
|
||||
- **位置**: BarcodeExtractTime 之后
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ SQL脚本
|
||||
|
||||
### 1️⃣ 新建表完整SQL
|
||||
|
||||
**文件**: `CreateLabelPdfCacheTable_Complete.sql`
|
||||
|
||||
```sql
|
||||
CREATE TABLE `label_pdf_cache` (
|
||||
...
|
||||
`BarcodeExtractTime` datetime DEFAULT NULL COMMENT '条码提取完成时间',
|
||||
`ParseDurationMs` int DEFAULT NULL COMMENT 'PDF解析花费的时间(毫秒)',
|
||||
...
|
||||
)
|
||||
```
|
||||
|
||||
### 2️⃣ 添加字段SQL
|
||||
|
||||
**文件**: `AddParseDurationMsField.sql`
|
||||
|
||||
```sql
|
||||
ALTER TABLE label_pdf_cache
|
||||
ADD COLUMN ParseDurationMs INT DEFAULT NULL COMMENT 'PDF解析花费的时间(毫秒)'
|
||||
AFTER BarcodeExtractTime;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💻 代码修改
|
||||
|
||||
### 1. 实体类修改 (LabelPdfCache.cs)
|
||||
|
||||
```csharp
|
||||
/// <summary>
|
||||
/// PDF解析花费的时间(毫秒)
|
||||
/// </summary>
|
||||
[SugarColumn(IsNullable = true)]
|
||||
public int? ParseDurationMs { get; set; }
|
||||
```
|
||||
|
||||
### 2. 时间记录逻辑 (LabelPdfCacheService.cs)
|
||||
|
||||
**方法开始处**:
|
||||
```csharp
|
||||
private async Task<bool> ProcessSingleCacheTask(string waybillNumber, LabelPdfCache? existingCache = null)
|
||||
{
|
||||
var startTime = DateTime.UtcNow; // ⭐ 记录开始时间
|
||||
try
|
||||
{
|
||||
// 处理逻辑...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**计算解析时间**:
|
||||
```csharp
|
||||
var parseDurationMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||
```
|
||||
|
||||
**在各个阶段记录**:
|
||||
```csharp
|
||||
// 验证失败时
|
||||
var duration = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||
await UpdateCacheStatus(existingCache, waybillNumber, 2, errorMsg, retryCount, duration);
|
||||
|
||||
// 验证成功时
|
||||
var parseDurationMs = (int)(DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||
await SaveCacheAsync(..., parseDurationMs: parseDurationMs);
|
||||
```
|
||||
|
||||
### 3. 方法签名更新
|
||||
|
||||
**SaveCacheAsync**:
|
||||
```csharp
|
||||
public async Task<bool> SaveCacheAsync(
|
||||
string waybillNumber, byte[] pdfBytes, int pageCount, int fileSize,
|
||||
string? originalUrl = null,
|
||||
string? finalMileTrackingNumber = null, int? customerId = null,
|
||||
string? barcodeNumber = null, byte barcodeType = 0,
|
||||
int? barcodeConfidence = null,
|
||||
int? parseDurationMs = null) // ⭐ 新增参数
|
||||
```
|
||||
|
||||
**UpdateCacheStatus**:
|
||||
```csharp
|
||||
private async Task UpdateCacheStatus(
|
||||
LabelPdfCache? existingCache, string waybillNumber,
|
||||
byte status, string errorMessage, int retryCount,
|
||||
int? parseDurationMs = null) // ⭐ 新增参数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 记录时间的场景
|
||||
|
||||
| 场景 | 记录时间 | 说明 |
|
||||
|------|---------|------|
|
||||
| PDF验证失败(页数超出) | ✅ 有 | 从开始到验证失败所用时间 |
|
||||
| PDF验证失败(文件过大) | ✅ 有 | 从开始到验证失败所用时间 |
|
||||
| PDF验证成功 | ✅ 有 | 从开始到完成条码识别所用时间 |
|
||||
| HTTP下载错误 | ❌ 无 | 会记录到错误日志中 |
|
||||
| Base64解析错误 | ❌ 无 | 会记录到错误日志中 |
|
||||
|
||||
---
|
||||
|
||||
## 📝 示例数据
|
||||
|
||||
### 缓存表中的数据示例
|
||||
|
||||
```
|
||||
| Id | NeutralWaybillNumber | ParseDurationMs | Status | BarcodeNumber |
|
||||
|----|----------------------|-----------------|--------|---------------|
|
||||
| 1 | 202605130001 | 245 | 1 | 1234567890 |
|
||||
| 2 | 202605130002 | 532 | 1 | NULL |
|
||||
| 3 | 202605130003 | 89 | 2 | NULL |
|
||||
| 4 | 202605130004 | 1523 | 1 | 9876543210 |
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- 245ms: 快速处理(可能是简单PDF)
|
||||
- 532ms: 中等处理(包含条码识别)
|
||||
- 89ms: 非常快(只是验证,未保存)
|
||||
- 1523ms: 较慢处理(复杂PDF + 条码识别)
|
||||
|
||||
---
|
||||
|
||||
## 🔍 使用场景
|
||||
|
||||
### 1. 性能分析
|
||||
|
||||
```sql
|
||||
-- 查询平均解析时间
|
||||
SELECT AVG(ParseDurationMs) as AvgDuration, COUNT(*) as Total
|
||||
FROM label_pdf_cache
|
||||
WHERE Status = 1;
|
||||
|
||||
-- 查询最慢的10条记录
|
||||
SELECT NeutralWaybillNumber, ParseDurationMs
|
||||
FROM label_pdf_cache
|
||||
ORDER BY ParseDurationMs DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
### 2. 监控告警
|
||||
|
||||
```sql
|
||||
-- 找出解析时间超过5秒的记录(可能表示性能问题)
|
||||
SELECT NeutralWaybillNumber, ParseDurationMs
|
||||
FROM label_pdf_cache
|
||||
WHERE ParseDurationMs > 5000
|
||||
AND Status = 1;
|
||||
```
|
||||
|
||||
### 3. 优化评估
|
||||
|
||||
```sql
|
||||
-- 按日期统计平均解析时间的变化趋势
|
||||
SELECT DATE(CreatedTime) as Date,
|
||||
AVG(ParseDurationMs) as AvgDuration,
|
||||
MIN(ParseDurationMs) as MinDuration,
|
||||
MAX(ParseDurationMs) as MaxDuration,
|
||||
COUNT(*) as ProcessCount
|
||||
FROM label_pdf_cache
|
||||
WHERE Status = 1
|
||||
GROUP BY DATE(CreatedTime)
|
||||
ORDER BY Date DESC;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 日志输出示例
|
||||
|
||||
```
|
||||
[2026-05-13 10:30:45] INFO: Processing cache task for waybill: SFN202605130001
|
||||
[2026-05-13 10:30:45] DEBUG: Successfully rendered PDF to bitmap using GhostScript, size: 800x1200
|
||||
[2026-05-13 10:30:46] INFO: Successfully saved cache for waybill: SFN202605130001
|
||||
└─ ParseDurationMs: 532ms
|
||||
|
||||
[2026-05-13 10:30:47] WARN: PDF page count exceeded for waybill: SFN202605130002, pages: 3, duration: 89ms
|
||||
[2026-05-13 10:30:47] INFO: Updated cache status for waybill: SFN202605130002
|
||||
└─ ParseDurationMs: 89ms
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 验证清单
|
||||
|
||||
```
|
||||
✅ 实体类字段已添加
|
||||
✅ 建表SQL已更新
|
||||
✅ 添加字段SQL已创建
|
||||
✅ SaveCacheAsync方法已更新
|
||||
✅ UpdateCacheStatus方法已更新
|
||||
✅ 接口定义已更新
|
||||
✅ 时间记录逻辑已实现
|
||||
✅ 编译成功(exit code = 0)
|
||||
✅ 零编译错误
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 SQL脚本执行步骤
|
||||
|
||||
### 新环境部署
|
||||
|
||||
```bash
|
||||
# 执行完整建表脚本
|
||||
mysql> source CreateLabelPdfCacheTable_Complete.sql;
|
||||
|
||||
# 验证字段
|
||||
mysql> DESC label_pdf_cache;
|
||||
# 应该看到 ParseDurationMs INT 字段
|
||||
```
|
||||
|
||||
### 现有环境升级
|
||||
|
||||
```bash
|
||||
# 1. 备份现有数据(重要!)
|
||||
mysql> BACKUP TABLE label_pdf_cache TO '/backup/';
|
||||
|
||||
# 2. 执行添加字段脚本
|
||||
mysql> source AddParseDurationMsField.sql;
|
||||
|
||||
# 3. 验证字段添加成功
|
||||
mysql> SELECT COLUMN_NAME, COLUMN_TYPE
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'label_pdf_cache'
|
||||
AND COLUMN_NAME = 'ParseDurationMs';
|
||||
|
||||
# 应该返回:
|
||||
# COLUMN_NAME: ParseDurationMs
|
||||
# COLUMN_TYPE: int(11)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 性能提示
|
||||
|
||||
1. **不需要索引**
|
||||
- ParseDurationMs 字段无需单独索引
|
||||
- 通常用于分析而不是查询过滤
|
||||
|
||||
2. **存储空间影响**
|
||||
- INT 字段占用4字节
|
||||
- 每条记录增加4字节(原为NULL时)
|
||||
- 影响微小
|
||||
|
||||
3. **查询建议**
|
||||
```sql
|
||||
-- 如果频繁按解析时间范围查询,可添加索引
|
||||
CREATE INDEX IX_ParseDurationMs ON label_pdf_cache (ParseDurationMs);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 预期数据分布
|
||||
|
||||
基于物流标签PDF通常的特点:
|
||||
|
||||
| 解析时间范围 | 比例 | 场景 |
|
||||
|----------|------|------|
|
||||
| < 100ms | 5% | 缓存中检验失败的记录 |
|
||||
| 100-500ms | 60% | 简单PDF,无或简单条码 |
|
||||
| 500-1000ms | 25% | 复杂PDF,有条码识别 |
|
||||
| 1000-2000ms | 9% | 超大文件或GhostScript不可用 |
|
||||
| > 2000ms | 1% | 异常情况 |
|
||||
|
||||
---
|
||||
|
||||
**所有代码和SQL脚本已准备好!** ✅
|
||||
|
||||
现在您可以:
|
||||
1. 在新环境使用完整建表SQL
|
||||
2. 在现有环境执行添加字段SQL
|
||||
3. 自动记录每个PDF的解析时间
|
||||
4. 用于性能分析和优化
|
||||
Reference in New Issue
Block a user