我很想了解(也许是改进)我在PostgreSQL 9.6中遇到的一个问题。名称简化了,但其他内容都是从psql
会话中提取的。
我从一个物化视图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慢呢?再慢多了!它是否利用了平行工人,如果不是,原因何在?
开始编辑
如下所示,我加载了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 ms才能运行!
总结我的问题:
STABLE
SQL函数中的SQL查询没有比函数外部的查询慢得多的参数。EXPLAIN ANALYZE
时SQL查询要慢得多?提前感谢!
发布于 2017-04-03 01:40:27
对于1),您可以使用auto_explain
了解自己,它可以显示函数内部查询的计划。它使用平行计划吗?
对于2)这是测量的开销,这取决于平台,但可以是高的。
3)比较两种情况下的SQL计划。SQL函数中的查询没有缓存,因此我没有解释为什么它应该这样运行。您是否多次重复测试以排除从磁盘读取和从缓存读取的效果?
https://stackoverflow.com/questions/43170330
复制