繁体   English   中英

获取 PostgreSQL 查询的执行时间

[英]Get execution time of PostgreSQL query

DECLARE @StartTime datetime,@EndTime datetime

SELECT @StartTime=GETDATE()

select distinct born_on.name
from   born_on,died_on
where (FLOOR(('2012-01-30'-born_on.DOB)/365.25) <= (
    select max(FLOOR((died_on.DOD - born_on.DOB)/365.25))
    from   died_on, born_on
    where (died_on.name=born_on.name))
    )
and   (born_on.name <> All(select name from died_on))

SELECT @EndTime=GETDATE()

SELECT DATEDIFF(ms,@StartTime,@EndTime) AS [Duration in millisecs]

我无法获得查询时间。 相反,我收到以下错误:

sql:/home/an/Desktop/dbms/query.sql:9: ERROR:  syntax error at or near "@"
LINE 1: DECLARE @StartTime datetime,@EndTime datetime

如果您的意思是在 psql 中,而不是您正在编写的某个程序,请使用\\? 如需帮助,请参阅:

\timing [on|off]       toggle timing of commands (currently off)

然后你会得到如下输出:

# \timing on
Timing is on.

# select 1234;        
 ?column? 
----------
     1234
(1 row)

Time: 0.203 ms

有多种方法可以衡量执行时间,每种方法都各有利弊。 但无论你做什么,都会有一定程度的观察者效应 即,测量本身可能会扭曲结果。

1.解释EXPLAIN ANALYZE

您可以添加EXPLAIN ANALYZE ,它会报告整个查询计划以及实际测量时间的估计成本。 查询实际执行(带有所有副作用,如果有的话!)。 适用于SELECTINSERTUPDATEDELETE

检查我修改后的查询版本是否实际上更快:

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
    );

执行几次以获得更多的热缓存可比时间。 有几个选项可用于调整细节级别。

虽然主要对总执行时间感兴趣,但让它:

EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)

大多数情况下, TIMING重要 -手册:

TIMING

在输出中包括实际启动时间和在每个节点上花费的时间。 在某些系统上,重复读取系统时钟的开销会显着降低查询速度,因此当只需要实际行计数而不是确切时间时,将此参数设置为FALSE可能很有用。 始终测量整个语句的运行时间,即使使用此选项关闭节点级计时也是如此。 [...]

EXPLAIN ANALYZE在服务器上测量,使用来自服务器操作系统的服务器时间,不包括网络延迟 但是EXPLAIN增加了一些开销来输出查询计划。

2. 带\\timing psql

或者在 psql 中使用\\timing 就像彼得展示的那样。

手册:

\\timing [ on | off ]

使用参数,打开或关闭显示每个 SQL 语句花费的时间。 如果没有参数,则在打开和关闭之间切换显示。 显示单位为毫秒; 超过 1 秒的间隔也以分钟:秒格式显示,如果需要,可以添加小时和天字段。

重要区别: psql 使用本地操作系统的本地时间在客户端上进行测量,因此时间包括网络延迟 根据连接和返回数据的数量,这可能是微不足道的差异或巨大的差异。

3. 启用log_duration

这可能是每次测量的开销最少,并且产生的时序失真最少。 但这有点笨手笨脚,因为您必须是超级用户,必须调整服务器配置,不能只针对单个查询的执行,而且您必须读取服务器日志(除非您重定向到stdout )。

手册:

log_duration ( boolean )

导致记录每个已完成语句的持续时间。 默认为off 只有超级用户才能更改此设置。

对于使用扩展查询协议的客户端,解析、绑定和执行步骤的持续时间是独立记录的。

有相关设置,如log_min_duration_statement

4. 使用clock_timestamp()精确的手动测量

手册:

clock_timestamp()返回实际的当前时间,因此即使在单个 SQL 命令中它的值也会发生变化。

为了尽可能准确地获得临时查询的执行时间,我能想到的最好的方法是基于filiprem 提供的内容- 这很好。
我对其进行了更多改进以过滤测量开销 - 这对于廉价查询可能很重要(但通常不适用于昂贵的查询) - 特别是如果底层操作系统使定时调用变得昂贵:

DO
$do$
DECLARE
   _start_ts1 timestamptz;
   _start_ts2 timestamptz;
   _start_ts  timestamptz;
   _end_ts1   timestamptz;
   _end_ts2   timestamptz;
   _end_ts    timestamptz;
   _overhead  numeric;     -- in ms
   _timing    numeric;     -- in ms
BEGIN
   _start_ts1 := clock_timestamp();
   _end_ts1   := clock_timestamp();
   _start_ts2 := clock_timestamp();
   _end_ts2   := clock_timestamp();
   -- take the minimum as conservative estimate
   _overhead  := 1000 * extract(epoch FROM LEAST(_end_ts1 - _start_ts1
                                               , _end_ts2 - _start_ts2));                     
   _start_ts := clock_timestamp();
   PERFORM 1;  -- your query here, replacing the outer SELECT with PERFORM
   _end_ts   := clock_timestamp();
   
   _timing := 1000 * (extract(epoch FROM _end_ts - _start_ts));
-- RAISE NOTICE 'Timing in ms = %'         , _timing;  -- optional info
-- RAISE NOTICE 'Timing overhead in ms = %', _overhead;
   RAISE NOTICE 'Execution time in ms = %' , _timing - _overhead;
END
$do$

计时本身的成本变化很大,具体取决于底层操作系统。 要掌握这一点,请几次开始和结束时间,并将最小间隔作为计时开销的保守估计。 此外,执行该函数几次应该会预热(如果需要)。

在测量负载查询的执行时间后,减去估计的开销以尽可能接近实际时间。

当然,如果可以的话,廉价查询循环 100000 次或在具有 100000 行的表上执行它更有意义,以使分散注意力的噪音变得无关紧要。

PostgreSQL 不是 Transact-SQL。 这是两件略有不同的事情。

在 PostgreSQL 中,这将类似于

DO $proc$
DECLARE
  StartTime timestamptz;
  EndTime timestamptz;
  Delta double precision;
BEGIN
  StartTime := clock_timestamp();
  PERFORM foo FROM bar; /* Put your query here, replacing SELECT with PERFORM */
  EndTime := clock_timestamp();
  Delta := 1000 * ( extract(epoch from EndTime) - extract(epoch from StartTime) );
  RAISE NOTICE 'Duration in millisecs=%', Delta;
END;
$proc$;

另一方面,测量查询时间不必如此复杂。 有更好的方法:

  1. postgres 命令行客户端中,有一个\\timing功能可以测量客户端的查询时间(类似于 SQL Server Management Studio 右下角的持续时间)。

  2. 可以在服务器日志中记录查询持续时间(对于每个查询,或者仅当它持续超过 X 毫秒时)。

  3. 可以使用EXPLAIN命令为任何单个语句收集服务器端计时:

     EXPLAIN (ANALYZE, BUFFERS) YOUR QUERY HERE;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM