应使用数据库内置高精度时间函数在存储过程内部手动打点计时:SQL Server用SYSDATETIME(),MySQL用NOW(6),PostgreSQL用CLOCK_TIMESTAMP(),并统一转UTC存储,避免外部工具、低精度函数或事务影响导致测量失真。

SQL Server 里怎么测存储过程真实执行时间
别信 SSMS 右下角那个“已用时间”,它只算网络往返+解析+显示耗时,不是存储过程实际运行时间。真要对比优化效果,得在过程内部掐秒表。
推荐用 SYS.DM_EXEC_SESSIONS 结合 GETDATE() 或更精确的 SYSDATETIME() 手动打点,尤其当过程含多次查询、循环或等待时,外部工具根本抓不准瓶颈在哪次调用。
- 用
DECLARE @start DATETIME2 = SYSDATETIME();开头,SELECT DATEDIFF(MICROSECOND, @start, SYSDATETIME())结尾,单位微秒,够细 - 避免用
GETDATE()(精度仅 3.3ms),高并发或短耗时过程下误差明显 - 如果过程里有
WAITFOR或远程调用,必须把打点放在EXEC前后,否则测的是“发起时间”而非“执行时间”
MySQL 存储过程中记录执行耗时的可行方案
MySQL 没有内置高精度计时器,NOW(6) 是唯一能到微秒级的函数,但要注意:它在存储过程中被调用时,可能因事务隔离级别或复制延迟产生偏差。
实操上更稳的方式是用 BENCHMARK() 配合日志表,或者干脆把耗时记录逻辑移到应用层——毕竟 MySQL 存储过程本身调试和监控能力弱,硬塞计时反而增加复杂度。
- 若坚持在过程内记录,用
DECLARE start_time TIME(6) DEFAULT NOW(6);+TIMEDIFF(NOW(6), start_time),但注意TIMEDIFF最大支持 838:59:59,超时会截断 - 别用
UNIX_TIMESTAMP()做差值——它返回秒级整数,丢失全部亚秒精度 - 写入日志表时加
INSERT INTO perf_log(proc_name, duration_us) VALUES ('xxx', ...),避免用SELECT输出,否则会被客户端工具干扰计时
PostgreSQL 函数中避免 EXPLAIN ANALYZE 干扰真实性能
EXPLAIN ANALYZE 看起来方便,但它会强制重跑一次查询,且开启额外统计开销,结果比实际业务调用慢 10%–30%,不能直接当优化依据。
真要评估,应该用 pg_stat_statements 插件采集生产环境真实调用数据,或在函数里用 CLOCK_TIMESTAMP() 手动埋点——它不受事务时间影响,比 NOW() 更准。
- 在函数开头写
DECLARE start_ts TIMESTAMPTZ := CLOCK_TIMESTAMP();,结尾RAISE NOTICE 'duration: %', EXTRACT(EPOCH FROM (CLOCK_TIMESTAMP() - start_ts)) * 1000000 || ' μs'; - 禁用
auto_explain模块做例行分析,它会在每次慢查询时自动触发,干扰正常执行节奏 - 如果函数调用了其他函数,
CLOCK_TIMESTAMP()在嵌套调用中依然有效,而STATEMENT_TIMESTAMP()会受事务起始时间影响,慎用
跨数据库统一记录执行时间的陷阱
想写个通用脚本对比不同库的存储过程性能?小心时间函数语义不一致:SYSDATETIME()(SQL Server)、NOW(6)(MySQL)、CLOCK_TIMESTAMP()(PostgreSQL)看着像,但一个依赖系统时钟,一个依赖事务快照,一个受同步复制延迟拖累。
更麻烦的是,有些数据库(如 Oracle)的 SYSTIMESTAMP 默认带时区,跨服务器比对前必须转成 UTC 再计算差值,否则同一条语句在不同时区机器上显示耗时不同。
- 所有时间戳入库前统一转成
UTC,用AT TIME ZONE 'UTC'(PostgreSQL)、SWITCHOFFSET(..., '+00:00')(SQL Server)、CONVERT_TZ(NOW(6), @@session.time_zone, '+00:00')(MySQL) - 别把毫秒值存成
INT,MySQL 的INT有符号上限是 2147483647(约 24.8 天),长期运行过程可能溢出 - 最隐蔽的坑:某些 ORM 或连接池(如 PgBouncer)会复用连接并重置会话变量,导致
SET LOCAL类计时开关失效,务必验证连接是否真的“干净”
真实环境里,存储过程执行时间波动常来自锁等待、磁盘 I/O 或计划缓存失效,光看 CPU 耗时没用。如果两次执行时间差一倍,先查 sys.dm_exec_requests(SQL Server)或 pg_stat_activity(PostgreSQL)里的 wait_type / wait_event,而不是急着改 SQL。


















