2017-04-02 97 views
2

我很好奇(并且可能改进)我在PostgreSQL 9.6中遇到的问题。名称简化,但其他所有内容均取自psql会话。了解查询中的COUNT行为与EXPLAIN与功能的比较

我从物化视图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=>\timing on

我可以非常迅速地计算从物化视图的结果。

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) 

好。所以它利用了多名工人。但是为什么在使用EXPLAIN ANALYZE时查询速度太慢?

现在我用的是count_mv()功能,它具有相同基础SQL和声明STABLE

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

Time: 406.058 ms 

哇!为什么这比物化视图上的同一个SQL更慢?而且慢很多!它是不是在利用平行工人,如果没有,为什么不呢?

BEGIN编辑

正如下面的答案提出的,我装了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名工人计划,但没有启动。服务器是空闲的,配置是相同的,并且查询是相同的。

编辑完

所有权利。那么,如果我这样做:

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

Time: 72.687 ms 

相同的性能,依靠物化视图行的情况下直接使用EXPLAIN ANALYZE,但你必须在这里相信我:这个功能的性能取决于的状态创建函数时的物化视图。这里的快速计时是在表格为空时创建函数的结果。如果我在桌子满了时重新创建功能,则该功能需要超过1000毫秒才能运行!

总结我的问题:

  1. 为什么不采取任何参数,远远低于该功能之外的查询STABLE SQL函数里面的SQL查询。
  2. 使用EXPLAIN ANALYZE时,为什么SQL查询,以便更慢?
  3. 为什么我得到的所有不同的结果从一个函数可以被等价快速对物化视图或慢行计数比任何其他方法,根据创建功能当计数行时?

在此先感谢!

回答

1

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

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

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

+0

感谢您的回复。 1)真棒模块。这对很多事情都会有帮助。对于新解释输出缺乏平行性的原因有什么想法? 2)明白了。说得通;惊讶它几乎是10倍。 3)是的。我多次尝试过这个测试。我甚至有两个具有相同SQL但具有不同创建时间的函数,我可以一个接一个地来回运行一个函数,并获得这些不同的结果。奇怪的! – rg6

+0

点3)对我来说还不清楚。我尝试过,但无法复制它。你能想出一个可重复的测试用例吗? –

+0

我添加了1)的编辑。获奖情况:您可以评论为什么函数内的相同SQL可能不会使用它计划的并行性。或者我误解了EXPLAIN输出? 3)你在测试用例中看到了哪些行为?不,我不能设法重现这一点,我知道这并不令人满意。昨天,我无法用快速的表现创建一个功能。今天,我无法创造一个表现缓慢的人。然而,具有不同性能的现有函数使用'\ df +'显示相同的代码。 – rg6