postgresql - 了解查询中的 COUNT 行为、EXPLAIN 与函数

标签 postgresql count sql-function explain postgresql-9.6

我很想了解(并可能改进)我在使用 PostgreSQL 9.6 时遇到的问题。名称已简化,但其他所有内容均取自 psql session 。

我从一个物化 View 开始,mv

首先,我创建了两个简单的函数:

CREATE FUNCTION count_mv() RETURNS BIGINT AS $$
SELECT COUNT(*) FROM mv;
$$ LANGUAGE SQL STABLE PARALLEL SAFE;

CREATE FUNCTION mv_pks() RETURNS TABLE (table_pk INTEGER) AS $$
SELECT table_pk FROM mv;
$$ LANGUAGE SQL STABLE PARALLEL SAFE;

让我们为一些查询计时。

db=>\计时

我可以非常快速地计算物化 View 的结果。

db=> SELECT COUNT(*) FROM mv;
  count
---------
 2567883
(1 row)

Time: 79.803 ms

让我们看看它是如何做到的。

db=> EXPLAIN ANALYZE SELECT COUNT(*) FROM mv;
                                                                  QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=41331.24..41331.25 rows=1 width=8) (actual time=765.681..765.681 rows=1 loops=1)
   ->  Gather  (cost=41330.62..41331.23 rows=6 width=8) (actual time=765.557..765.670 rows=7 loops=1)
         Workers Planned: 6
         Workers Launched: 6
         ->  Partial Aggregate  (cost=40330.62..40330.63 rows=1 width=8) (actual time=760.175..760.175 rows=1 loops=7)
               ->  Parallel Seq Scan on mv  (cost=0.00..39261.09 rows=427809 width=0) (actual time=0.014..397.952 rows=366840 loops=7)
 Planning time: 0.326 ms
 Execution time: 769.934 ms
(8 rows)

很好。所以它利用了多个 worker 。但是,为什么使用 EXPLAIN ANALYZE 时查询速度如此之慢?

现在我使用 count_mv() 函数,它具有 相同 底层 SQL 并被声明为 STABLE

db=> select count_mv();
  count_mv
------------
    2567883
(1 row)

Time: 406.058 ms

哇哦!为什么这比物化 View 上的相同 SQL 慢?而且慢很多!它是否没有利用并行 worker ,如果没有,为什么不呢?

开始编辑

按照下面的回答中的建议,我加载了 auto_explain 模块并在函数调用时检查了 EXPLAIN 的日志输出。

    Query Text:
    SELECT COUNT(*) FROM mv;

     Finalize Aggregate  (cost=41331.60..41331.61 rows=1 width=8) (actual time=1345.446..1345.446 rows=1 loops=1)
       ->  Gather  (cost=41330.97..41331.58 rows=6 width=8) (actual time=1345.438..1345.440 rows=1 loops=1)
            Workers Planned: 6
            Workers Launched: 0
             ->  Partial Aggregate  (cost=40330.97..40330.99 rows=1 width=8) (actual time=1345.435..1345.435 rows=1 loops=1)
                  ->  Parallel Seq Scan on mv  (cost=0.00..39261.38 rows=427838 width=0) (actual time=0.020..791.022 rows=2567883 loops=1)

新的问题是为什么计划了 6 个 worker 而没有启动。其他服务器空闲,配置相同,查询相同。

结束编辑

好的。那么如果我这样做呢:

db=> SELECT COUNT(*) FROM mv_pks();
  count
---------
 2567883
(1 row)

Time: 72.687 ms

与不使用 EXPLAIN ANALYZE 直接在实体化 View 上计算行数的性能相同,但是你必须在这里相信我:这个函数的性能取决于实体化 View 的状态该功能已创建。这里的快速计时是在表为空时创建函数的结果。如果我在表已满时重新创建该函数,该函数需要超过 1000 毫秒才能运行!

总结一下我的问题:

  1. 为什么 STABLE SQL 函数内的 SQL 查询不带参数比该函数外的查询慢得多。
  2. 为什么使用 EXPLAIN ANALYZE 时 SQL 查询速度如此之慢?
  3. 为什么我在计算一个函数的行数时会得到所有不同的结果,这个函数要么比计算实体化 View 上的行数快,要么慢于任何其他方法,具体取决于函数的创建时间?

提前致谢!

最佳答案

对于 1),您可以使用 auto_explain 找到自己,它可以显示函数内部查询的计划。它是否使用并行计划?

对于 2),这是测量的开销,这取决于平台,但可能很高。

对于 3) 比较两种情况下的 SQL 计划。 SQL 函数中的查询没有被缓存,所以我没有解释为什么它会这样。您是否多次重复测试以排除您看到从磁盘读取与从缓存读取的效果?

关于postgresql - 了解查询中的 COUNT 行为、EXPLAIN 与函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43170330/

相关文章:

django - 带有 Django 和 postgres 的 Heroku 应用程序意外崩溃

postgresql - Docker容器中的Postgresql版本与其数据不兼容

当数据库为空时,MySQL COUNT 查询返回行

sql - PGSQL - 如何在另一个查询中使用 select 语句的输出?

postgresql - pgpoolAdmin 无法在步骤 2 之后继续

mysql - 按每个值 COUNT 排序

java - java中计算hashmap中每个值对应的条目数的逻辑

sql-server - SQL Server : function return column values that can be used in where clause?

sql - 将存储过程转换为表值查询

java - 使用 Spring jdbc 执行 Oracle 函数