衡量执行时间的方法多种多样,各有利弊.但无论你做什么,observer effect的某些程度都适用.也就是说,测量本身可能会扭曲结果.
1. EXPLAIN ANALYZE
您可以预先输入EXPLAIN ANALYZE
,它会报告整个查询计划,以及实际测量的估计成本时间.查询结果是actually executed(如果有副作用的话,还有所有副作用!).为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可用于调整细节级别.
虽然主要对total execution time感兴趣,但要做到:
EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)
通常情况下,TIMING
件事——the manual:件事
TIMING
在输出中包括实际启动时间和每个 node 花费的时间.
EXPLAIN ANALYZE
使用服务器操作系统excluding network latency的服务器时间测量on the server.但是EXPLAIN
也为输出查询计划增加了一些开销.
2. psql with \timing
或者在psql中使用\timing
.Like Peter demonstrates.
The manual:
\timing [ on | off ]
通过一个参数,可以显示每条SQL语句的长度
Important difference: psql使用本地操作系统的本地时间测量on the client,因此时间为includes network latency.这可能是一个可以忽略不计的差异,也可能是huge,具体取决于连接和返回数据的量.
3. Enable log_duration
这可能是每次测量的开销最小,并且产生的计时失真最少.但这有点麻烦,因为你必须是超级用户,必须调整服务器配置,不能只针对单个查询的执行,还必须读取服务器日志(log)(除非重定向到stdout
).
The manual:
log_duration
(boolean
)
导致记录每个已完成语句的持续时间.这个
对于使用扩展查询协议的客户端,解析的持续时间,
有一些相关的设置,比如log_min_duration_statement
.
4. Precise manual measurement with clock_timestamp()
The manual:
clock_timestamp()
返回实际的当前时间,因此即使在单个SQL命令中,其值也会发生变化.
filiprem provided a great way to get execution times for ad-hoc queries as exact as possible. On modern hardware, timing overhead should be insignificant but depending on the host OS it can vary wildly. Find out with the server application pg_test_timing
.
Else you can mostly filter the overhead like this:
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个时间戳进行最小值),并 Select 最小间隔作为定时开销的保守估计.此外,执行函数clock_timestamp()
几次应该会使其预热(以防这对操作系统很重要).
在测量有效负载查询的执行时间后,减go 估计的开销以接近实际时间.
当然,对于便宜的查询来说,循环10万次或在一个有10万行的表上执行它(如果可以的话),让分散注意力的噪音变得无关紧要,这更有意义.