DBMS_UTILITY.GET_TIME 返回自实例启动以来的百分之一秒(10毫秒单位),非毫秒;最小分辨率为10ms,故相减结果为整数、可能跳变或负数。
DBMS_UTILITY.GET_TIME 返回的是百分之一秒,不是毫秒
很多人误以为 dbms_utility.get_time 能直接拿到毫秒值,结果发现两次调用相减总是整数、跳变明显,甚至出现负数。它返回的是「自数据库实例启动以来的百分之一秒(centisecond)」,也就是 10 毫秒为单位——所以最小分辨率是 10ms,不是 1ms。
这意味着:如果你代码执行时间 GET_TIME 很可能返回相同值;若在 10–19ms 区间,它只显示 1;20–29ms 显示 2……本质是向下取整到最近的 10ms 倍数。
- 别用它测单条 SQL 或极短 PL/SQL 块,误差太大
- 适合粗粒度对比:比如两个存储过程整体耗时差异是否超过几十毫秒
- 跨会话调用要小心:不同会话看到的起始时间基准一致,但系统时钟漂移或实例重启会影响绝对值
正确计算耗时的写法:相减后乘 10 得到毫秒近似值
虽然不能精确到毫秒,但只要理解单位,就能合理换算。关键不是“怎么转成毫秒”,而是“怎么避免除法截断”和“怎么规避会话状态干扰”。
典型错误写法:elapsed := end_time - start_time / 100; —— 这里除法优先级导致结果错乱。
- 必须先做减法,再乘 10:
elapsed_ms := (end_time - start_time) * 10; - 变量类型推荐用
NUMBER或PLS_INTEGER,避免隐式转换丢失精度 - 如果想打印更可读,可以四舍五入到整数:
ROUND((end_time - start_time) * 10) - 注意:该值仍是近似值,实际误差 ±5ms
比 GET_TIME 更准的替代方案:DBMS_PROFILER 或 DBMS_SESSION
当真需要毫秒级定位瓶颈(比如函数内某段逻辑到底卡在哪),DBMS_UTILITY.GET_TIME 就力不从心了。Oracle 自带的分析工具更可靠。
-
DBMS_PROFILER可逐行统计执行次数和时间(需提前开启、收集、分析三步) -
DBMS_SESSION.SLEEP(0.01)配合GET_TIME可验证单位是否生效(但别在生产用) - 12c+ 推荐用
DBMS_MONITOR+ ASH 数据,查V$ACTIVE_SESSION_HISTORY中的TIME_WAITED字段(单位微秒) - 简单脚本调试?不如直接用 SQL*Plus 的
SET TIMING ON,它底层调用更高精度计时器
容易被忽略的陷阱:时区、RAC 节点、自治事务干扰
你以为只是个简单的减法,其实背后藏着几个隐蔽雷区。
- RAC 环境下,不同节点的
GET_TIME基准可能有微小偏差,跨节点计时不建议直接比较 - 在自治事务(
AUTONOMOUS_TRANSACTION)里调用GET_TIME,返回值仍属于父会话的时间线,不是自治事务独立计时 - 数据库时间受 OS 时钟影响;如果 DB 主机做了 NTP 校正,
GET_TIME可能突变(虽少见,但监控告警时要注意) - 不要在循环里高频调用——它本身有开销,频繁调用反而扭曲被测代码的真实耗时
真正要压测或调优,得结合 AWR 报告看 DB Time 和 SQL 执行计划,而不是靠几个 GET_TIME 点位猜。


















