mysql中需用timestampdiff(second, start_time, end_time)转秒数再avg(),postgresql用extract(epoch from (end_time - start_time)),直接avg(end_time - start_time)在mysql报错、postgresql结果不可靠。

用 AVG() 和时间差计算平均停留时长
直接对时间字段做 AVG() 会出错,因为大多数数据库(如 MySQL、PostgreSQL)不支持对 DATETIME 类型直接求平均。必须先转成数值单位(秒或毫秒),再求均值。
常见错误是写成 AVG(end_time - start_time) —— 这在 PostgreSQL 可能侥幸运行,但在 MySQL 会报错或返回 0,因为减法结果不是数值类型。
- MySQL:用
TIMESTAMPDIFF(SECOND, start_time, end_time)得到整数秒数 - PostgreSQL:用
EXTRACT(EPOCH FROM (end_time - start_time)) - SQL Server:用
DATEDIFF(second, start_time, end_time)
示例(MySQL):
SELECT node_name, AVG(TIMESTAMPDIFF(SECOND, enter_time, exit_time)) AS avg_seconds<br>FROM process_log<br>GROUP BY node_name;
区分“停留”和“处理”需明确字段语义
很多流程表里只有 enter_time 和 exit_time,但“停留时长”通常指进入节点到离开节点的时间,“处理时长”则可能剔除等待时间(比如有 start_work_time 字段)。混淆这两者会导致统计失真。
- 若只有
enter_time和exit_time,默认按停留时长算 - 若有
start_work_time和finish_work_time,才建议用它们算处理时长 - 注意空值:
start_work_time IS NULL的记录会拉低平均值,应显式过滤或用CASE WHEN排除
示例(排除空处理时间):
SELECT node_name,<br> AVG(TIMESTAMPDIFF(SECOND, start_work_time, finish_work_time)) AS avg_handle_sec<br>FROM process_log<br>WHERE start_work_time IS NOT NULL AND finish_work_time IS NOT NULL<br>GROUP BY node_name;
按节点流转顺序聚合时,别漏掉首尾节点的边界情况
一个流程实例可能跨多个节点,但每条日志只记录单个节点。如果想统计“从 A 到 B 的平均耗时”,不能只靠单节点字段,得关联前后行 —— 这时 LAG() 或自连接就必要了。
- 用
LAG(exit_time) OVER (PARTITION BY process_id ORDER BY seq)获取上一节点退出时间 - 当前节点
enter_time - 上一节点 exit_time才是等待/切换耗时 - 首节点没有前置节点,
LAG()返回 NULL,需用COALESCE或WHERE过滤 - 索引要覆盖
(process_id, seq),否则窗口函数性能会陡降
时区与精度问题常被忽略
如果 enter_time 和 exit_time 是 TIMESTAMP WITHOUT TIME ZONE,而业务分布在多个时区,直接相减可能偏差数小时。更隐蔽的是毫秒精度丢失:MySQL 5.6 默认只存秒级,NOW() 插入后毫秒全为 0。
- 检查字段类型:
DESCRIBE process_log看是否为TIMESTAMP(3)或TIMESTAMP(6) - 统一时区写入:应用层或触发器中用
CONVERT_TZ(NOW(), '+00:00', '+08:00') - 测试数据里手动插入带毫秒的时间,验证
TIMESTAMPDIFF(MICROSECOND, ...)是否返回非零值
平均值本身对异常值敏感,一个卡住三天的节点会让整个节点平均值失真,生产环境建议同时查 PERCENTILE_CONT(0.5)(中位数)作对照。











