衡量执行时间的方法有很多种,各有利弊。但无论你做什么,一定程度的observer effect 都适用。即,测量本身可能会扭曲结果。
1。 EXPLAIN ANALYZE
您可以在前面加上EXPLAIN ANALYZE,它会报告整个查询计划以及实际测量时间的估计成本。查询实际执行(如果有的话,还有所有的副作用!)。适用于SELECT、INSERT、UPDATE、DELETE。
检查我修改后的查询是否实际上更快:
EXPLAIN ANALYZE
SELECT DISTINCT born_on.name
FROM born_on b
WHERE date '2012-01-30' - b.dob <= (
SELECT max(d1.dod - b1.dob)
FROM born_on b1
JOIN died_on d1 USING (name) -- name must be unique!
)
AND NOT EXISTS (
SELECT FROM died_on d2
WHERE d2.name = b.name
);
使用热缓存执行几次以获得更多可比较的时间。 Several options 可用于调整详细程度。
虽然主要对总执行时间感兴趣,但要做到:
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
大多数情况下,TIMING 很重要 - the manual:
TIMING
在输出中包含实际启动时间和在每个节点上花费的时间。
重复读取系统时钟的开销会减慢
在某些系统上显着查询,因此设置它可能很有用
FALSE 的参数,当只有实际的行数,而不是确切的时间时,
是需要的。始终测量整个语句的运行时间,即使
当使用此选项关闭节点级时序时。 [...]
EXPLAIN ANALYZE在服务器上测量,使用来自服务器操作系统的服务器时间,不包括网络延迟。但是EXPLAIN 增加了一些开销来输出查询计划。
2。 psql 与\timing
或者在 psql 中使用\timing。 Like Peter demonstrates.
The manual:
\timing [ on | off ]
带参数,轮流显示每条SQL语句的时长
开启或关闭。没有参数,在显示之间切换
和关闭。显示以毫秒为单位;间隔长于 1
秒也以分钟:秒格式显示,带有小时和天
如果需要,添加字段。
重要区别: psql 在客户端使用本地操作系统的本地时间进行测量,因此时间包括网络延迟。这可能是微不足道的差异,也可能是巨大,具体取决于连接和返回数据的数量。
3。启用log_duration
这可能每次测量的开销最小,并且产生的时序失真最小。但这有点笨拙,因为您必须是超级用户,必须调整服务器配置,不能只针对单个查询的执行,并且您必须阅读服务器日志(除非您重定向到 stdout)。
The manual:
log_duration (boolean)
导致记录每个已完成语句的持续时间。这
默认为off。只有超级用户才能更改此设置。
对于使用扩展查询协议的客户端,解析的持续时间,
绑定和执行步骤是独立记录的。
有log_min_duration_statement等相关设置。
4。使用clock_timestamp() 进行精确的手动测量
The manual:
clock_timestamp() 返回实际的当前时间,因此即使在单个 SQL 命令中其值也会发生变化。
filiprem provided 是获得尽可能准确的即席查询执行时间的好方法。在现代硬件上,时间开销应该是微不足道的,但取决于主机操作系统,它可能会有很大差异。通过服务器应用程序pg_test_timing 查找。
否则,您主要可以像这样过滤开销:
DO
$do$
DECLARE
_timing1 timestamptz;
_start_ts timestamptz;
_end_ts timestamptz;
_overhead numeric; -- in ms
_timing numeric; -- in ms
BEGIN
_timing1 := clock_timestamp();
_start_ts := clock_timestamp();
_end_ts := clock_timestamp();
-- take minimum duration as conservative estimate
_overhead := 1000 * extract(epoch FROM LEAST(_start_ts - _timing1
, _end_ts - _start_ts));
_start_ts := clock_timestamp();
PERFORM 1; -- your query here, replacing the outer SELECT with PERFORM
_end_ts := clock_timestamp();
-- RAISE NOTICE 'Timing overhead in ms = %', _overhead;
RAISE NOTICE 'Execution time in ms = %' , 1000 * (extract(epoch FROM _end_ts - _start_ts)) - _overhead;
END
$do$;
重复计算时间(这里用 3 个时间戳计算最少的时间),然后选择最小间隔作为计时开销的保守估计。此外,多次执行函数 clock_timestamp() 应该会对其进行预热(以防这对您的操作系统很重要)。
测量负载查询的执行时间后,减去估计的开销以更接近实际时间。
当然,对于廉价查询来说,循环 100000 次或在有 100000 行的表上执行它更有意义,以使分散注意力的噪音变得微不足道。