【问题标题】:Get COUNT() result within time limit在时限内获取 COUNT() 结果
【发布时间】:2016-06-08 19:44:11
【问题描述】:

PostgreSQL 中有没有办法中止COUNT(*) 语句的执行并返回其当前结果?

我想跑步:

SELECT COUNT(*) FROM table WHERE something=x;

有些查询几乎很快就完成了,但有些则需要相当长的时间。我想要:

  • 如果语句在时限内完成,则返回 final 结果,
  • 否则它会中止执行但返回当前结果。

如果也能获得退出状态(无论它是完成执行还是被中止)也会很好。

我找到了statement_timeout 设置,但它不返回任何结果,只是中止。

【问题讨论】:

    标签: sql postgresql count postgresql-performance


    【解决方案1】:

    您可以轻松地指示 Postgres 计数到给定的 LIMIT - 最大行数,而不是经过的时间:

    SELECT count(*)
    FROM  (
       SELECT 1 FROM tbl
       WHERE  something = 'x'
       LIMIT  100000  -- stop counting at 100k
       ) sub;
    

    如果count() 需要很长时间,您的设置可能有巨大 表或其他一些问题。无论哪种方式,估计的计数都足以满足您的目的:

    在最长经过时间后停止计数本身是不可能的。您可以使用上述技术对计数进行分区,并在每一步后检查经过的时间。但这会增加很多的开销。使用OFFSET 跳过行并不比计算它们便宜多少。我不认为我会使用它。就像概念证明一样:

    DO
    $do$
    DECLARE
       _partition bigint := 100000;  -- size of count partition
       _timeout   timestamptz := clock_timestamp() + interval '1s';  -- max time allowed
       _round     int := 0;
       _round_ct  bigint;
    BEGIN
    
    LOOP
       SELECT count(*)
       FROM (
          SELECT 1 FROM tbl
          WHERE  something = 'x'
          LIMIT  _partition
          OFFSET _partition * _round
          ) sub
       INTO   _round_ct;
    
       IF _round_ct < _partition THEN
          RAISE NOTICE 'count: %; status: complete', _partition * _round + _round_ct;
          RETURN;
       ELSIF clock_timestamp() > _timeout THEN
          RAISE NOTICE 'count: %; status: timeout', _partition * _round + _round_ct;
          RETURN;
       END IF;
    
       _round := _round + 1;
    END LOOP;
    
    END
    $do$;
    

    您可以将其包装在 plpgsql 函数中并传递参数。甚至使它适用于 任何 给定的表/列 EXECUTE ...

    如果您的 ID 列几乎没有空白,那么该技术会更有意义。您可以按 ID 进行分区,而开销要少得多...

    【讨论】:

    • 感谢您回答和编辑问题。对不起我的英语:) 我想,count 需要一段时间,因为它必须加入所有其他表。我放弃了这个想法,并用标准化来换取性能。
    • @Dmitry:通常,您可以同时拥有:标准化性能。 materialized view 可能会有所帮助。
    【解决方案2】:

    我认为在查询完成并使其对最终用户(也就是您)可见之前,您永远不会获得带有计数的结果集。这就是 ACID 数据库的基本规则。从启动 SELECT 命令开始,您要求获取当时行数的快照。

    您最好从另一个角度看待问题,并通过对查询执行 EXPLAIN 来了解为什么某些查询需要很长时间,然后调查结果。

    【讨论】:

      猜你喜欢
      • 2013-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 1970-01-01
      • 2016-05-07
      • 2014-04-28
      • 1970-01-01
      相关资源
      最近更新 更多