【问题标题】:Get execution time of PostgreSQL query获取PostgreSQL查询的执行时间
【发布时间】:2012-01-30 11:48:30
【问题描述】:
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

【问题讨论】:

  • 我在我的 SQL 工作室测试了这个查询,只是用我的数据库中的东西替换了你的 select distinct...,它工作正常。你用什么来执行这个查询?
  • m 在 postgres 中运行上述查询!! :-/
  • 你到底想做什么?这似乎与 Java 或 JDBC 无关(从您的评论来看,甚至与 MySql 无关)。这是一个存储过程吗?
  • MySQL 和 PostgreSQL 是非常不同的东西(好像将 Teradata 与 Oracle 与 Access 进行比较)。如果您使用的是 PostgreSQL,那么您应该删除 MySLQ 标志 :)
  • @zyxwvu:那你为什么在一个针对 PostgreSQL 但使用 Microsoft SQL 语法的问题中包含 MySQL 标记?您收到的错误消息是 MySQL 错误,而不是 PostgreSQL 错误。

标签: sql postgresql performance timing


【解决方案1】:

如果您指的是 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

【讨论】:

  • 感谢您对这个问题的标题给出简单而基本的答案。
  • 我这是在 postgres 中显示时间的最直接和最简单的方法。谢谢!
  • 这显示的是服务器端时间还是客户端(延迟)?文档对此只字未提。
  • @CrouchingKitten 我用一个非常慢的互联网进行了测试,使用本地 unix 域套接字连接得到了“0.261 毫秒”,并且使用 TCP 上的 psql 获得了“944.272 毫秒”:D。因此,它只能是客户端。
  • @CrouchingKitten:客户端 - 与 EXPLAIN ANALYZE 报告的总执行时间相反,它在服务器上测量(没有网络延迟)。
【解决方案2】:

衡量执行时间的方法有很多种,各有利弊。但无论你做什么,一定程度的observer effect 都适用。即,测量本身可能会扭曲结果。

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

使用热缓存执行几次以获得更多可比较的时间。 Several options 可用于调整详细程度。

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

EXPLAIN (ANALYZE, COSTS OFF, TIMING OFF)

大多数情况下,TIMING 很重要 - the manual:

TIMING

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

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

2。 psql 与\timing

或者在 psql 中使用\timingLike 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 行的表上执行它更有意义,以使分散注意力的噪音变得微不足道。

【讨论】:

  • 很好 (+1) - 像往常一样彻底。我认为您所说的"measurement problem 可能更好地称为observer effect
  • @Vérace:是的,谢谢,这显然是更好的术语。
【解决方案3】:

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 command line client 中有一个\timing 功能可以测量客户端的查询时间(类似于SQL Server Management Studio 右下角的持续时间)。

  2. 可以record query duration in server log(对于每个查询,或仅当它持续时间超过 X 毫秒时)。

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

    EXPLAIN (ANALYZE, BUFFERS) YOUR QUERY HERE;
    

【讨论】:

  • 提及\timing
  • @filiperm 最好将Delta定义为double precision
  • 很好的答案,而且有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-12
  • 2015-12-17
  • 2016-02-11
  • 1970-01-01
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
相关资源
最近更新 更多