首页 > 数据库 >postgresql -- 执行计划

postgresql -- 执行计划

时间:2023-04-18 11:37:30浏览次数:40  
标签:rows postgresql .. -- Worker time loops actual 执行


一、 显示执行计划

pg中explain命令格式如下

explain [options] sql语句

例如
explain select * from test;
explain (format xml) select * from test;
explain (analyze true,buffers true) select * from test;

options可选项如下:

  • ANALYZE(默认FALSE):实际执行sql,显示真实的执行计划及返回行数
  • VERBOSE(默认FALSE):显示附加信息,如计划树中每个节点输出的各个列、表和函数的SCHEMA 信息,表达式中列所属表的别名,被触发的触发器名(如果有用到)等
  • COSTS(默认TRUE):显示每个计划启动成本、总成本、预估长度及每行宽度
  • BUFFERS(默认FALSE):显示缓冲区使用信息,只能与ANALYZE一起使用。缓冲区信息包括共享块(常规表或者索引块)、本地块(临时表或者索引块)和临时块(排序或者哈希等涉及到的短期存在的数据块)的命中块数,更新块数,挤出块数。
  • TIMING(默认TRUE):显示每个计划节点的实际启动时间和总执行时间,只能与ANALYZE一起使用。对于一些系统来说,获取系统时间需要比较大的代价,如果只需要准确返回行数,而不需要准确的时间,可以把该参数关闭。
  • SUMMARY(默认FALSE):会在查询计划后面输出总结信息,例如查询计划生成的时间和查询执行的时间。当启用ANALYZE 时,默认TRUE。
  • FORMAT {TEXT | XML | JSON | YAML} (默认TEXT):指定输出格式

如果要分析慢SQL到底慢在哪里,使用 explain (analyze,verbose,timing,costs,buffers,timing) SQL;就可以,再加上一些开关,可以看到更加详细的信息。

--开关, 当前会话生效,打印更加详细的信息
set client_min_messages=debug5;
set log_checkpoints = on;
set log_error_verbosity = verbose ;
set log_lock_waits = on;                  
set log_replication_commands = off;
set log_temp_files = 0;
set track_activities = on;
set track_counts = on;
set track_io_timing = on;
set track_functions = 'all';
set trace_sort=on;
set log_statement_stats = off;
set log_parser_stats = on;
set log_planner_stats = on;
set log_executor_stats = on;
set log_autovacuum_min_duration=0;
set deadlock_timeout = '1s';
set debug_print_parse = off;
set debug_print_rewritten = off;
set debug_print_plan = off;
set debug_pretty_print = on;
 
--例如
explain (analyze,verbose,timing,costs,buffers) select count(*),relkind from pg_class group by relkind order by count(*) desc limit 1;

二、 执行计划解释

1. 执行计划含义

 EXPLAIN SELECT * FROM tenk1;
                             QUERY PLAN
    -------------------------------------------------------------
     Seq Scan on tenk1  (cost=0.00..458.00 rows=10000 width=244)
     
 cost=0.00..458.00 (具体计算参考后文)

  •     0.00为预计的启动开销(返回第一行需要多少cost)
  •     458.00为预计的总开销(返回所有行需要多少cost)

rows=10000   

  • 预计的该规划节点输出的行数

width=244

  • 预计的该规划节点的行平均宽度(单位:字节)

2. 扫描类型

目前在PostgreSQL 中支持的扫描如下:

  • Seq Scan,顺序扫描
  • Index Scan,基于索引扫描,但不只是返回索引列的值
  • IndexOnly Scan,基于索引扫描,并且只返回索引列的值,简称为覆盖索引
  • BitmapIndex Scan,利用Bitmap 结构扫描
  • BitmapHeap Scan,把BitmapIndex Scan 返回的Bitmap 结构转换为元组结构
  • Tid Scan,用于扫描一个元组TID 数组
  • Subquery Scan,扫描一个子查询
  • Function Scan,处理含有函数的扫描
  • TableFunc Scan,处理tablefunc 相关的扫描
  • Values Scan,用于扫描Values 链表的扫描
  • Cte Scan,用于扫描WITH 字句的结果集
  • NamedTuplestore Scan,用于某些命名的结果集的扫描
  • WorkTable Scan,用于扫描Recursive Union 的中间数据
  • Foreign Scan,用于外键扫描
  • Custom Scan,用于用户自定义的扫描

下面只介绍一些常见的类型:

Seq Scan:全表扫描

postgres=> explain(ANALYZE,VERBOSE,BUFFERS) select * from class where st_no=2;
                                               QUERY PLAN
--------------------------------------------------------------------------------------------------------
 Seq Scan on public.class  (cost=0.00..26.00 rows=1 width=35) (actual time=0.136..0.141 rows=1 loops=1)
   Output: st_no, name
   Filter: (class.st_no = 2)
   Rows Removed by Filter: 1199
   Buffers: shared hit=11
 Planning time: 0.066 ms
 Execution time: 0.160 ms
  • Seq Scan on public.class 表明了这个节点的类型和作用对象,即在class 表上进行了全表扫描
  • (cost=0.00..26.00 rows=1 width=35) 表明了这个节点的代价估计,这部分我们将在下文节点代价估计信息中详细介绍
  • (actual time=0.136..0.141 rows=1 loops=1) 表明了这个节点的真实执行信息,当EXPLAIN 命令中的ANALYZE选项为on时,会输出该项内容,具体的含义我们将在下文节点执行信息中详细介绍
  • Output: st_no, name 表明了SQL 的输出结果集的各个列,当EXPLAIN 命令中的选项VERBOSE 为on时才会显示
  • Filter: (class.st_no = 2) 表明了Seq Scan 节点之上的Filter 操作,即全表扫描时对每行记录进行过滤操作,过滤条件为class.st_no = 2
  • Rows Removed by Filter: 1199 表明了过滤操作过滤了多少行记录,属于Seq Scan 节点的VERBOSE 信息,只有EXPLAIN 命令中的VERBOSE 选项为on 时才会显示
  • Buffers: shared hit=11 表明了从共享缓存中命中了11 个BLOCK,属于Seq Scan 节点的BUFFERS 信息,只有EXPLAIN 命令中的BUFFERS 选项为on 时才会显示
  • Planning time: 0.066 ms 表明了生成查询计划的时间
  • Execution time: 0.160 ms 表明了实际的SQL 执行时间,其中不包括查询计划的生成时间

Index Scan:索引扫描加回表,相当于sqlserver index seek + key lookup

postgres=> explain(ANALYZE,VERBOSE,BUFFERS) select * from class where st_no=2;
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Index Scan using no_index on public.class  (cost=0.28..8.29 rows=1 width=35) (actual time=0.022..0.023 rows=1 loops=1)
   Output: st_no, name
   Index Cond: (class.st_no = 2)
   Buffers: shared hit=3
 Planning time: 0.119 ms
 Execution time: 0.060 ms
(6 rows)
  • Index Scan using no_index on public.class 表明是使用的public.class 表的no_index 索引对表进行索引扫描的
  • Index Cond: (class.st_no = 2) 表明索引扫描的条件是class.st_no = 2

可以看出,使用了索引之后,对相同表的相同条件的扫描速度变快了。这是因为从全表扫描变为索引扫描,通过Buffers: shared hit=3 可以看出,需要扫描的BLOCK(或者说元组)少了,所以需要的代价也就小了,速度也就快了。

Index-Only Scan:不需要回表的索引扫描

IndexOnly Scan 是覆盖索引扫描,所需的返回结果能被所扫描的索引全部覆盖,例如上面Index Scan中的SQL 把“select * ” 修改为“select st_no” ,其EXPLAIN 结果输出如下:

postgres=> explain(ANALYZE,VERBOSE,BUFFERS) select st_no from class where st_no=2;
                                                         QUERY PLAN
-------------------------------------------------------------------------------------------
 Index Only Scan using no_index on public.class  (cost=0.28..4.29 rows=1 width=4) (actual time=0.015..0.016 rows=1 loops=1)
   Output: st_no
   Index Cond: (class.st_no = 2)
   Heap Fetches: 0
   Buffers: shared hit=3
 Planning time: 0.058 ms
 Execution time: 0.036 ms
(7 rows)
  • Index Only Scan using no_index on public.class 表明使用public.class 表的no_index 索引对表进行覆盖索引扫描
  • Heap Fetches 表明需要扫描数据块的个数。

虽然Index Only Scan 可以从索引直接输出结果。但是因为MVCC 机制的实现,需要对扫描的元组进行可见性判断,即检查visibility MAP 文件。当新建表之后,如果没有进行过vacuum和autovacuum操作,这时还没有VM文件,而索引并没有保存记录的版本信息,索引Index Only Scan 还是需要扫描数据块(Heap Fetches 代表需要扫描的数据块个数)来获取版本信息,这时可能会比Index Scan 慢。

BitmapIndex Scan 与BitmapHeap Scan

BitmapIndex Scan 与Index Scan 很相似,都是基于索引的扫描,但是BitmapIndex Scan 节点每次执行返回的是一个位图而不是一个元组,其中位图中每位代表一个扫描到的数据块。BitmapHeap Scan一般会作为BitmapIndex Scan 的父节点,将BitmapIndex Scan 返回的位图转换为对应的元组。这样做最大的好处就是把Index Scan 的随机读转换成了按照数据块的物理顺序读取,在数据量比较大的时候,这会大大提升扫描的性能。

常见情况:多个字段均有索引,又有and/or、非等值查询、in子句等

postgres=# explain analyze select id,deptno from gaotab where id=100 or id=300;

QUERY PLAN                                                         
-------------------------------------------------------------------------------------------
 Bitmap Heap Scan on gaotab  (cost=8.52..13.34 rows=2 width=8) (actual time=31.201..31.227 rows=2 loops=1)
   Recheck Cond: ((id = 100) OR (id = 300))
   ->  BitmapOr  (cost=8.52..8.52 rows=2 width=0) (actual time=13.738..13.738 rows=0 loops=1)
         ->  Bitmap Index Scan on idx_id_dept  (cost=0.00..4.26 rows=1 width=0) (actual time=13.729..13.729 rows=1 loops=1)
               Index Cond: (id = 100)
         ->  Bitmap Index Scan on idx_id_dept  (cost=0.00..4.26 rows=1 width=0) (actual time=0.008..0.008 rows=1 loops=1)
               Index Cond: (id = 300)

Total runtime: 42.876 ms
(8 rows)
  • Index Cond: (id = 300) 表明位图索引的条件为id = 300
  • Bitmap Index Scan on idx_id_dept 表明使用idx_id_dept索引进行位图索引扫描
  • BitmapOr 进行or操作
  • Recheck Cond: ((id = 100) OR (id = 300)) 表明Bitmap Heap Scan 的recheck操作条件是id = 100 OR id = 300。Bitmap Index Scan 节点返回的是位图,位图中每位代表了一个扫描到的数据块,通过位图可以定位到一些符合条件的数据块,而Bitmap Heap Scan 则需要对每个数据块的元组进行Recheck
  • Bitmap Heap Scan on gaotab 表明对gaotab表进行Bitmap Heap 扫描

至此,我们对这几种主要的扫描节点有了一些认识。一般来说:

  • 大多数情况下,Index Scan 要比 Seq Scan 快。但是如果获取的结果集占所有数据的比重很大时,这时Index Scan 因为要先扫描索引再读表数据反而不如直接全表扫描来的快。
  • 如果获取的结果集的占比比较小,但是元组数很多时,可能Bitmap Index Scan 的性能要比Index Scan 好。
  • 如果获取的结果集能够被索引覆盖,则Index Only Scan 因为不用去读数据,只扫描索引,性能一般最好。但是如果VM 文件未生成,可能性能就会比Index Scan 要差。

上面的结论都是基于理论分析得到的结果,但是其实PostgreSQL 的EXPLAIN 命令中输出的cost,rows,width 等代价估计信息中已经展示了这些扫描节点或者其他节点的预估代价,通过对预估代价的比较,可以选择出最小代价的查询计划树。

3. 表连接

  • Nest loop join:将返回子集较小的表作为外表,且内表连接字段上要有索引
  • Hash join:使用两个表中较小的表,并利用连接键在内存中建立hash表,然后扫描较大的表并在hash表中找出匹配的行
  • Merge join:若源数据上有索引或结果已排过序,Merge join的性能会优于Hash join

三、慢SQL优化示例

1. 查看真实的执行计划

begin;  
set local lock_timeout='1s';  
set local statement_timeout=0;  
explain (analyze,verbose,timing,costs,buffers,timing) SQL;  -- SQL代替为要分析的SQL  
rollback;

2. 从explain结果中,找到最耗时的NODE

postgres=#  explain (analyze,verbose,timing,costs,buffers) select count(*),c34 from test where c33<3 group by c34;   
                      QUERY PLAN             
---------------------------------------------------------------------------------------------------------------  
 HashAggregate  (cost=18042933.67..18042933.78 rows=11 width=16) (actual time=79898.384..79898.386 rows=11 loops=1)  
   Output: count(*), c34  
   Group Key: test.c34  
   Buffers: shared hit=3296 read=16663371  
   ->  Seq Scan on public.test  (cost=0.00..17916667.00 rows=25253334 width=8) (actual time=0.065..74406.748 rows=24997473 loops=1)  大量耗费  
         Output: id, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15, c16, c17, c18, c19, c20, c21, c22, c23, c24, c25, c26, c27, c28, c29, c30, c31, c32, c33, c34, c35, c36, c37, c38, c39, c40, c41, c42, c43, c44, c45, c46, c47, c48, c49, c50, c51, c52, c53, c54, c55, c56, c57, c58, c59, c60, c61, c62, c63, c64  
         Filter: (test.c33 < 3)  
         Rows Removed by Filter: 75002527  过滤了大量的行,但是还有很多行需要被查询  
         Buffers: shared hit=3296 read=16663371  
 Planning Time: 0.096 ms  
 Execution Time: 79898.435 ms  
(11 rows)

3. 针对NODE进行优化

3.1 以上例子,实际上就是扫描花费了很多时间,并且扫描后过滤的结果占比比较低,可以使用索引解决。

postgres=# create index idx on test (c33,c34);  
  
postgres=# explain (analyze,verbose,timing,costs,buffers) select count(*),c34 from test where c33<3 group by c34;   
                                                                    QUERY PLAN                                                                      
--------------------------------------------------------------------------------------------------------------------------------------------------  
 HashAggregate  (cost=685855.26..685855.37 rows=11 width=16) (actual time=8056.793..8056.795 rows=11 loops=1)  
   Output: count(*), c34  
   Group Key: test.c34  
   Buffers: shared hit=112642  
   ->  Index Only Scan using idx on public.test  (cost=0.57..557588.60 rows=25653333 width=8) (actual time=0.031..3691.071 rows=24997473 loops=1)  
         Output: c33, c34  
         Index Cond: (test.c33 < 3)  
         Heap Fetches: 0  
         Buffers: shared hit=112642   扫描了多少 index 数据块   
 Planning Time: 0.166 ms  
 Execution Time: 8056.842 ms  
(11 rows)

3.2 聚集后的优化,并行。

postgres=# set max_parallel_workers_per_gather =32;  
SET  
postgres=#  explain (analyze,verbose,timing,costs,buffers) select count(*),c34 from test where c33<3 group by c34;   
                                                                                QUERY PLAN                                                                                  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
 Finalize GroupAggregate  (cost=318089.48..318125.45 rows=11 width=16) (actual time=999.918..1000.053 rows=11 loops=1)  
   Output: count(*), c34  
   Group Key: test.c34  
   Buffers: shared hit=9623  
   ->  Gather Merge  (cost=318089.48..318124.02 rows=264 width=16) (actual time=999.768..999.973 rows=275 loops=1)  
         Output: c34, (PARTIAL count(*))  
         Workers Planned: 24  
         Workers Launched: 24  
         Buffers: shared hit=9623  
         ->  Sort  (cost=317088.90..317088.93 rows=11 width=16) (actual time=926.196..926.198 rows=11 loops=25)  
               Output: c34, (PARTIAL count(*))  
               Sort Key: test.c34  
               Sort Method: quicksort  Memory: 25kB  
               Worker 0:  Sort Method: quicksort  Memory: 25kB  
               Worker 1:  Sort Method: quicksort  Memory: 25kB  
               Worker 2:  Sort Method: quicksort  Memory: 25kB  
               Worker 3:  Sort Method: quicksort  Memory: 25kB  
               Worker 4:  Sort Method: quicksort  Memory: 25kB  
               Worker 5:  Sort Method: quicksort  Memory: 25kB  
               Worker 6:  Sort Method: quicksort  Memory: 25kB  
               Worker 7:  Sort Method: quicksort  Memory: 25kB  
               Worker 8:  Sort Method: quicksort  Memory: 25kB  
               Worker 9:  Sort Method: quicksort  Memory: 25kB  
               Worker 10:  Sort Method: quicksort  Memory: 25kB  
               Worker 11:  Sort Method: quicksort  Memory: 25kB  
               Worker 12:  Sort Method: quicksort  Memory: 25kB  
               Worker 13:  Sort Method: quicksort  Memory: 25kB  
               Worker 14:  Sort Method: quicksort  Memory: 25kB  
               Worker 15:  Sort Method: quicksort  Memory: 25kB  
               Worker 16:  Sort Method: quicksort  Memory: 25kB  
               Worker 17:  Sort Method: quicksort  Memory: 25kB  
               Worker 18:  Sort Method: quicksort  Memory: 25kB  
               Worker 19:  Sort Method: quicksort  Memory: 25kB  
               Worker 20:  Sort Method: quicksort  Memory: 25kB  
               Worker 21:  Sort Method: quicksort  Memory: 25kB  
               Worker 22:  Sort Method: quicksort  Memory: 25kB  
               Worker 23:  Sort Method: quicksort  Memory: 25kB  
               Buffers: shared hit=207494  
               Worker 0: actual time=923.125..923.126 rows=11 loops=1  
                 Buffers: shared hit=8571  
               Worker 1: actual time=922.567..922.568 rows=11 loops=1  
                 Buffers: shared hit=7575  
               Worker 2: actual time=923.209..923.210 rows=11 loops=1  
                 Buffers: shared hit=8448  
               Worker 3: actual time=922.613..922.615 rows=11 loops=1  
                 Buffers: shared hit=7958  
               Worker 4: actual time=923.265..923.266 rows=11 loops=1  
                 Buffers: shared hit=8706  
               Worker 5: actual time=923.329..923.330 rows=11 loops=1  
                 Buffers: shared hit=8800  
               Worker 6: actual time=923.298..923.299 rows=11 loops=1  
                 Buffers: shared hit=8637  
               Worker 7: actual time=922.778..922.780 rows=11 loops=1  
                 Buffers: shared hit=7168  
               Worker 8: actual time=923.348..923.349 rows=11 loops=1  
                 Buffers: shared hit=8804  
               Worker 9: actual time=923.303..923.304 rows=11 loops=1  
                 Buffers: shared hit=8576  
               Worker 10: actual time=923.270..923.272 rows=11 loops=1  
                 Buffers: shared hit=8848  
               Worker 11: actual time=923.308..923.309 rows=11 loops=1  
                 Buffers: shared hit=8500  
               Worker 12: actual time=923.415..923.417 rows=11 loops=1  
                 Buffers: shared hit=8606  
               Worker 13: actual time=922.827..922.828 rows=11 loops=1  
                 Buffers: shared hit=7402  
               Worker 14: actual time=923.307..923.309 rows=11 loops=1  
                 Buffers: shared hit=8415  
               Worker 15: actual time=922.994..922.996 rows=11 loops=1  
                 Buffers: shared hit=7467  
               Worker 16: actual time=923.456..923.457 rows=11 loops=1  
                 Buffers: shared hit=8460  
               Worker 17: actual time=923.364..923.366 rows=11 loops=1  
                 Buffers: shared hit=8647  
               Worker 18: actual time=923.287..923.289 rows=11 loops=1  
                 Buffers: shared hit=8549  
               Worker 19: actual time=922.968..922.969 rows=11 loops=1  
                 Buffers: shared hit=7211  
               Worker 20: actual time=923.361..923.363 rows=11 loops=1  
                 Buffers: shared hit=8650  
               Worker 21: actual time=923.178..923.179 rows=11 loops=1  
                 Buffers: shared hit=7691  
               Worker 22: actual time=923.129..923.131 rows=11 loops=1  
                 Buffers: shared hit=7609  
               Worker 23: actual time=923.427..923.428 rows=11 loops=1  
                 Buffers: shared hit=8573  
               ->  Partial HashAggregate  (cost=317088.60..317088.71 rows=11 width=16) (actual time=926.136..926.138 rows=11 loops=25)  
                     Output: c34, PARTIAL count(*)  
                     Group Key: test.c34  
                     Buffers: shared hit=207326  
                     Worker 0: actual time=923.055..923.058 rows=11 loops=1  
                       Buffers: shared hit=8564  
                     Worker 1: actual time=922.506..922.509 rows=11 loops=1  
                       Buffers: shared hit=7568  
                     Worker 2: actual time=923.159..923.162 rows=11 loops=1  
                       Buffers: shared hit=8441  
                     Worker 3: actual time=922.551..922.553 rows=11 loops=1  
                       Buffers: shared hit=7951  
                     Worker 4: actual time=923.220..923.223 rows=11 loops=1  
                       Buffers: shared hit=8699  
                     Worker 5: actual time=923.285..923.288 rows=11 loops=1  
                       Buffers: shared hit=8793  
                     Worker 6: actual time=923.254..923.257 rows=11 loops=1  
                       Buffers: shared hit=8630  
                     Worker 7: actual time=922.695..922.698 rows=11 loops=1  
                       Buffers: shared hit=7161  
                     Worker 8: actual time=923.290..923.293 rows=11 loops=1  
                       Buffers: shared hit=8797  
                     Worker 9: actual time=923.254..923.256 rows=11 loops=1  
                       Buffers: shared hit=8569  
                     Worker 10: actual time=923.223..923.226 rows=11 loops=1  
                       Buffers: shared hit=8841  
                     Worker 11: actual time=923.224..923.226 rows=11 loops=1  
                       Buffers: shared hit=8493  
                     Worker 12: actual time=923.373..923.376 rows=11 loops=1  
                       Buffers: shared hit=8599  
                     Worker 13: actual time=922.766..922.769 rows=11 loops=1  
                       Buffers: shared hit=7395  
                     Worker 14: actual time=923.232..923.235 rows=11 loops=1  
                       Buffers: shared hit=8408  
                     Worker 15: actual time=922.935..922.938 rows=11 loops=1  
                       Buffers: shared hit=7460  
                     Worker 16: actual time=923.406..923.409 rows=11 loops=1  
                       Buffers: shared hit=8453  
                     Worker 17: actual time=923.317..923.319 rows=11 loops=1  
                       Buffers: shared hit=8640  
                     Worker 18: actual time=923.204..923.206 rows=11 loops=1  
                       Buffers: shared hit=8542  
                     Worker 19: actual time=922.893..922.895 rows=11 loops=1  
                       Buffers: shared hit=7204  
                     Worker 20: actual time=923.283..923.286 rows=11 loops=1  
                       Buffers: shared hit=8643  
                     Worker 21: actual time=923.089..923.092 rows=11 loops=1  
                       Buffers: shared hit=7684  
                     Worker 22: actual time=923.049..923.051 rows=11 loops=1  
                       Buffers: shared hit=7602  
                     Worker 23: actual time=923.379..923.381 rows=11 loops=1  
                       Buffers: shared hit=8566  
                     ->  Parallel Index Only Scan using idx on public.test  (cost=0.57..311744.15 rows=1068889 width=8) (actual time=0.294..726.243 rows=999899 loops=25)  
                           Output: c33, c34  
                           Index Cond: (test.c33 < 3)  
                           Heap Fetches: 0  
                           Buffers: shared hit=207326  
                           Worker 0: actual time=0.249..739.989 rows=1028079 loops=1  
                             Buffers: shared hit=8564  
                           Worker 1: actual time=0.500..698.527 rows=912456 loops=1  
                             Buffers: shared hit=7568  
                           Worker 2: actual time=0.449..733.146 rows=1010592 loops=1  
                             Buffers: shared hit=8441  
                           Worker 3: actual time=0.554..712.277 rows=953955 loops=1  
                             Buffers: shared hit=7951  
                           Worker 4: actual time=0.088..736.872 rows=1047915 loops=1  
                             Buffers: shared hit=8699  
                           Worker 5: actual time=0.172..734.815 rows=1056267 loops=1  
                             Buffers: shared hit=8793  
                           Worker 6: actual time=0.052..737.294 rows=1040346 loops=1  
                             Buffers: shared hit=8630  
                           Worker 7: actual time=0.086..696.398 rows=862866 loops=1  
                             Buffers: shared hit=7161  
                           Worker 8: actual time=0.051..735.082 rows=1053918 loops=1  
                             Buffers: shared hit=8797  
                           Worker 9: actual time=0.336..740.511 rows=1031994 loops=1  
                             Buffers: shared hit=8569  
                           Worker 10: actual time=0.496..735.275 rows=1063836 loops=1  
                             Buffers: shared hit=8841  
                           Worker 11: actual time=0.238..728.468 rows=1016595 loops=1  
                             Buffers: shared hit=8493  
                           Worker 12: actual time=0.049..737.655 rows=1035648 loops=1  
                             Buffers: shared hit=8599  
                           Worker 13: actual time=0.302..699.745 rows=888966 loops=1  
                             Buffers: shared hit=7395  
                           Worker 14: actual time=0.200..729.542 rows=1011114 loops=1  
                             Buffers: shared hit=8408  
                           Worker 15: actual time=0.296..695.864 rows=898623 loops=1  
                             Buffers: shared hit=7460  
                           Worker 16: actual time=0.070..734.046 rows=1015812 loops=1  
                             Buffers: shared hit=8453  
                           Worker 17: actual time=0.053..737.755 rows=1040868 loops=1  
                             Buffers: shared hit=8640  
                           Worker 18: actual time=0.081..737.488 rows=1030689 loops=1  
                             Buffers: shared hit=8542  
                           Worker 19: actual time=0.092..694.639 rows=870957 loops=1  
                             Buffers: shared hit=7204  
                           Worker 20: actual time=0.523..737.503 rows=1040607 loops=1  
                             Buffers: shared hit=8643  
                           Worker 21: actual time=1.978..709.165 rows=925182 loops=1  
                             Buffers: shared hit=7684  
                           Worker 22: actual time=0.294..699.942 rows=907497 loops=1  
                             Buffers: shared hit=7602  
                           Worker 23: actual time=0.120..739.781 rows=1030689 loops=1  
                             Buffers: shared hit=8566  
 Planning Time: 0.311 ms  
 Execution Time: 1007.876 ms  
(193 rows)

三、 执行计划相关配置项

1, ENABLE_*参数

相当于hint

enable_seqscan:是否选择全表扫描
enable_indexscan:是否选择索引扫描
enable_bitmapscan:是否选择位图扫描
enable_tidscan:是否tid扫描(类似oracle rowid)
enable_nestloop:多表连接时,是否选择嵌套循环连接
enable_hashjoin:多表连接时,是否选择hash连接
enable_mergejoin:多表连接时,是否选择merge连接
enable_hashagg:多表连接时,是否使用hash聚合
enable_sort:是否使用明确的排序

2. cost基准值参数

cost描述一个sql执行的代价是多少,除默认值外也可自行设定

  • 顺序扫描一个数据块   cost=1
  • 随机扫描一个数据块   cost=4
  • 处理一个数据行的CPU  cost=0.01
  • 处理一个索引行的CPU  cost=0.005
  • 执行每个操作符或函数的CPU代价  cost=0.0025
seq_page_cost:执行计划中一次顺序访问一个数据块页面的开销,默认1.0
random_page_cost:随机访问一个数据块页面的开销,默认4.0
cpu_tuple_cost:执行计划中,处理一条数据行的开销,默认0.01
cpu_idex_tuple_cost:处理一条索引行的开销,默认0.005
cpu_operator_cost:执行一个操作符或函数的开销,默认0.0025
effective_cache_size:执行计划中在一次索引扫描中可用的磁盘缓冲区的有效大小。默认128MB

3. 基因查询用户参数

基因查询优化(GEQO)使用探索式搜索执行查询规划,可降低规划时间,但生成的执行计划有不确定性

geqo:允许和禁止基因查询优化
geqo_threshold:只当涉及的from关系数量至少有这么多个时,才使用基因查询优化。
geqo_effort:控制geqo里规划时间和查询规划有效性直接的平衡。默认5,1-10
geqo_pool_size:控制geqo使用池的大小
geqo_generations:控制geqo使用的子代数目,子代意思算法的迭代次数
geqo_selection_bias:控制geqo使用的选择性偏好
geqo_seed:控制geqo使用的随机数产生器的初始值,用以选择随机路径。

4. 其他执行计划配置项

postgresql -- 执行计划_数据库

postgresql -- 执行计划_数据库_02

postgresql -- 执行计划_SQL_03

postgresql -- 执行计划_SQL_04

参考

【PG执行计划】Postgresql数据库执行计划统计信息简述_ITPUB博客

PgSQL · 最佳实践 · EXPLAIN 使用浅析

标签:rows,postgresql,..,--,Worker,time,loops,actual,执行
From: https://blog.51cto.com/u_13631369/6202736

相关文章

  • Hutool工具类常用工具
    介绍Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大......
  • vue中使两个不同高度的div(内容长度不一)高度相同
    设置高度height,记得给左右侧div一个最小高度min-height,保证没有内容的时候有一定的高度,内容撑起来的时候再自动适应<el-col:xs="12":sm="6":md="2"class="grid-cell"><divclass="grid-contentbg-purple":style="{height:divH......
  • Python认识爬虫与反爬虫
    爬虫:通过计算机去获取信息,以节约人力成本,不节约的就不需要用了。反爬虫的最终:区别计算机和人,从而达到,排除计算机的访问,允许人的访问。最终结论:爬虫与反爬虫都是有尽头的。爬虫的尽头就是极度模拟用户(自动化)。反爬虫的尽头就是机器无法识别而人类可以识别的验证码。所以,省事的......
  • 面对CICD分析的代码静态测试工具Klocwork 2023.1版本更新快讯
    前言  Klocwork2023.1为CI/CD分析pipeline引入灵活的管理选项。使用差异分析加速静态分析扫描,在CI/CD管道构建中提供上下文结果,并可以用和服务器端相同的方式管理issue。 扩展了对Java14/15和C#8.0语言的支持,C/C++/C#PATH分析性能提升高达50%*。此外,此版本还包括对M......
  • 动力节点2023最新MybatisPlus学习笔记(一)入门篇
    MyBatis是很火的框架,一般的项目都是基于ssm,虽然mybatis可以直接在xml中通过SQL语句操作数据库,很灵活,但其操作都要通过SQL语句进行,就必须写大量的xml文件,非常麻烦。而MyBatis-Plus可以很好的解决了这个问题,比Mybatis简单太多了,不用搞那么多xml文件的配置,直接与Springboot整合,开发效......
  • 强化学习奖励函数的设置
    奖励奖励强化学习中奖励函数设置不好,agent也得不到好的解。确定奖励函数的注意事项明确任务目标:一定要确保奖励函数和任务目标是一致的,否则可能会出现奖励函数引导agent在任务上取得不良的表现。注意:因为算法目标是最大化奖励,所以需要看奖励和目标之间的关系。当我的奖励......
  • DolphinDB 计算节点使用指南
    导读为了提升DolphinDB在高并发读写场景下的性能与稳定性,DolphinDB在架构上引入了计算节点(computenode) 。计算节点接管了数据节点的部分职能,负责响应客户端的请求并返回结果。在架构层面,将集群的计算与存储进行分离,保证数据节点的软硬件资源有效服务于IO过程,从而提升集群写......
  • Android Jar中实现另一个Jar中接口的解决办法
    |加固与逆向是一场永不停息的战争如题,今天在写jar包的时候遇到这样的一个问题,甲方呢想让我的jar包中的接口删除,然后jar包中的类去实现他们jar包中的接口,但是,我的jar包中又不能加载他们的jar包,看官老爷们可以想象一下当时操蛋的场景,没有接口,我的具体实现类就会报错,一报错就打包......
  • 解决img标签之间的间隙
    1)img{display:block};将其改变为block元素,但是该方法太过粗暴,相当于从根本上改变了img2)img{vertical-align:top;}改变其垂直对齐方式3)div{font-size:0};把父元素的文字大小设置为04)div{line-height:0};把父元素的行高设置为05)img{float:left};使用float进行浮动6)div......
  • Android_关于程序产生 65535 (64K)的解决办法
    随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误:UNEXPECTEDTOP-LEVELEXCEPTION:java.lang.IllegalArgumentException:methodIDnotin[0,0xffff]:65536atco......