본문 바로가기
DBMS/PostgreSQL

[PostgreSQL] SQL 실행계획 관리(pg_store_plans)

by 드바 2023. 12. 5.

 

OS: linux 7.5
DBMS: PostgreSQL 14.9

 

[목차여기]


PostgreSQL은 기본적으로 SQL 실행계획을 저장하지 않습니다. 
운영 시 SQL 실행 계획이 변경되었는지 확인하는 것은 중요한 부분 중 하나인데 그게 불가능한 것이죠. 
pg_store_plans이라는 extension을 사용하면 이 부분이 해결가능한데 pg_store_plans을 설치하고 간단하게 사용해 보는 테스트를 진행해 보겠습니다.
 

rpm 파일 다운

  • pg_store_plans rpm 파일 다운 사이트

https://github.com/ossc-db/pg_store_planshttps://github.com/ossc-db/pg_store_plans/releases
 

  • 플랫폼에 해당하는 rpm 다운로드

 

rpm 설치

[root@svr1 ~]# rpm -qa | grep store
abrt-addon-pstoreoops-2.1.11-50.0.1.el7.x86_64
[root@svr1 ~]# 
[root@svr1 ~]# 
[root@svr1 ~]# rpm -Uvh pg_store_plans14-1.6.1-1.el7.x86_64.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:pg_store_plans14-1.6.1-1.el7     ################################# [100%]
[root@svr1 ~]# rpm -qa | grep store
abrt-addon-pstoreoops-2.1.11-50.0.1.el7.x86_64
pg_store_plans14-1.6.1-1.el7.x86_64
[root@svr1 ~]#

 

postgresql.conf 파일 파라미터 수정(DB재기동 시 적용됨)

테스트는 pg_store_plans.min_duration = 1000(1초 이상 실행SQL만 수집) 파라미터만 변경하고 나머지는 그대로 진행하였음

shared_preload_libraries = 'pg_stat_statements,timescaledb,pg_hint_plan,pg_store_plans'
pg_store_plans.min_duration = 1000
-- 파라미터 확인
SELECT name, setting, unit 
FROM pg_catalog.pg_settings 
WHERE name LIKE '%pg_store%'
;
              name              | setting | unit 
--------------------------------+---------+------
 pg_store_plans.log_analyze     | off     | 
 pg_store_plans.log_buffers     | off     | 
 pg_store_plans.log_timing      | on      | 
 pg_store_plans.log_triggers    | off     | 
 pg_store_plans.log_verbose     | off     | 
 pg_store_plans.max             | 1000    | 
 pg_store_plans.max_plan_length | 5000    | 
 pg_store_plans.min_duration    | 1000    | 
 pg_store_plans.plan_format     | text    | 
 pg_store_plans.plan_storage    | file    | 
 pg_store_plans.save            | on      | 
 pg_store_plans.track           | top     | 
(12 rows)

 

pg_store_plans extension 생성

-- 설치된 extension 조회
SELECT name, default_version,installed_version
FROM pg_available_extensions 
WHERE name LIKE '%store%'
;
      name      | default_version | installed_version 
----------------+-----------------+-------------------
 hstore         | 1.8             | 
 hstore_plperl  | 1.0             | 
 hstore_plperlu | 1.0             | 
 pg_store_plans | 1.6.1           | 
(4 rows)

-- pg_store_plans 설치
sk1=# create extension pg_store_plans ;
CREATE EXTENSION

-- 설치 확인
SELECT name, default_version,installed_version
FROM pg_available_extensions 
WHERE name LIKE '%store%'
;
      name      | default_version | installed_version 
----------------+-----------------+-------------------
 hstore         | 1.8             | 
 hstore_plperl  | 1.0             | 
 hstore_plperlu | 1.0             | 
 pg_store_plans | 1.6.1           | 1.6.1
(4 rows)

 

테스트 SQL 실행

SELECT count(*) FROM tab100 a, tab100 b ;
  count   
----------
 68442529
(1 row)

Time: 5378.473 ms (00:05.378)

 

저장된 실행계획 조회

  • pg_stat_statements 와 조인하여 SQL별 실행 계획 조회
SELECT s.queryid, s.query
, p.planid
, p.plan
, p.calls AS "plan calls"
, s.calls AS "stmt calls"
, round(s.mean_exec_time::numeric/1000,2) AS avg_exec_sec
, (s.shared_blks_hit + s.shared_blks_read) shared_blks_io
, p.first_call, p.last_call
FROM pg_stat_statements s, pg_store_plans p
WHERE s.queryid = p.queryid
;
       queryid        |                  query                  |   planid   |                                     plan                                      | plan calls | stmt calls | avg_exec_sec | shared_blks_io |          first_call           |           last_call           
----------------------+-----------------------------------------+------------+-------------------------------------------------------------------------------+------------+------------+--------------+----------------+-------------------------------+-------------------------------
 -8852661820973207002 | SELECT count(*) FROM tab100 a, tab100 b | 2186412635 | Aggregate  (cost=1027208.08..1027208.09 rows=1 width=8)                      +|          1 |          6 |         5.34 |           2304 | 2023-12-05 17:34:03.126315+09 | 2023-12-05 17:34:03.126315+09
                      |                                         |            |   ->  Nested Loop  (cost=0.00..856101.76 rows=68442529 width=0)              +|            |            |              |                |                               | 
                      |                                         |            |         ->  Seq Scan on tab100 a  (cost=0.00..274.73 rows=8273 width=0)      +|            |            |              |                |                               | 
                      |                                         |            |         ->  Materialize  (cost=0.00..316.10 rows=8273 width=0)               +|            |            |              |                |                               | 
                      |                                         |            |               ->  Seq Scan on tab100 b  (cost=0.00..274.73 rows=8273 width=0) |            |            |              |                |                               | 
 -8852661820973207002 | explain (analyze, buffers)             +| 2186412635 | Aggregate  (cost=1027208.08..1027208.09 rows=1 width=8)                      +|          1 |          1 |        24.66 |            384 | 2023-12-05 17:34:03.126315+09 | 2023-12-05 17:34:03.126315+09
                      | SELECT count(*) FROM tab100 a, tab100 b+|            |   ->  Nested Loop  (cost=0.00..856101.76 rows=68442529 width=0)              +|            |            |              |                |                               | 
                      | ;                                       |            |         ->  Seq Scan on tab100 a  (cost=0.00..274.73 rows=8273 width=0)      +|            |            |              |                |                               | 
                      |                                         |            |         ->  Materialize  (cost=0.00..316.10 rows=8273 width=0)               +|            |            |              |                |                               | 
                      |                                         |            |               ->  Seq Scan on tab100 b  (cost=0.00..274.73 rows=8273 width=0) |            |            |              |                |                               | 
(2 rows)

 
 

  • 컬럼 세로로 결과 출력(\x on)
-- 컬럼 세로 모드로 출력
test=# \x on
Expanded display is on.
SELECT s.queryid, s.query
, p.planid
, p.plan
, p.calls AS "plan calls"
, s.calls AS "stmt calls"
, round(s.mean_exec_time::numeric/1000,2) AS avg_exec_sec
, (s.shared_blks_hit + s.shared_blks_read) shared_blks_io
, p.first_call, p.last_call
FROM pg_stat_statements s, pg_store_plans p
WHERE s.queryid = p.queryid
;

-[ RECORD 1 ]--+------------------------------------------------------------------------------
queryid        | -8852661820973207002
query          | SELECT count(*) FROM tab100 a, tab100 b
planid         | 2186412635
plan           | Aggregate  (cost=1027208.08..1027208.09 rows=1 width=8)                      +
               |   ->  Nested Loop  (cost=0.00..856101.76 rows=68442529 width=0)              +
               |         ->  Seq Scan on tab100 a  (cost=0.00..274.73 rows=8273 width=0)      +
               |         ->  Materialize  (cost=0.00..316.10 rows=8273 width=0)               +
               |               ->  Seq Scan on tab100 b  (cost=0.00..274.73 rows=8273 width=0)
plan calls     | 1
stmt calls     | 6
avg_exec_sec   | 5.34
shared_blks_io | 2304
first_call     | 2023-12-05 17:34:03.126315+09
last_call      | 2023-12-05 17:34:03.126315+09
-[ RECORD 2 ]--+------------------------------------------------------------------------------
queryid        | -8852661820973207002
query          | explain (analyze, buffers)                                                   +
               | SELECT count(*) FROM tab100 a, tab100 b                                      +
               | ;
planid         | 2186412635
plan           | Aggregate  (cost=1027208.08..1027208.09 rows=1 width=8)                      +
               |   ->  Nested Loop  (cost=0.00..856101.76 rows=68442529 width=0)              +
               |         ->  Seq Scan on tab100 a  (cost=0.00..274.73 rows=8273 width=0)      +
               |         ->  Materialize  (cost=0.00..316.10 rows=8273 width=0)               +
               |               ->  Seq Scan on tab100 b  (cost=0.00..274.73 rows=8273 width=0)
plan calls     | 1
stmt calls     | 1
avg_exec_sec   | 24.66
shared_blks_io | 384
first_call     | 2023-12-05 17:34:03.126315+09
last_call      | 2023-12-05 17:34:03.126315+09

 

기타

  • pg_store_plans 테이블 데이터 초기화
SELECT pg_store_plans_reset();
-- pg_store_plans 테이블 데이터 초기화
test=# SELECT pg_store_plans_reset();
-[ RECORD 1 ]--------+-
pg_store_plans_reset | 

test=# select count(*) from pg_store_plans ;
 count 
-------
     0
(1 row)

 

  • pg_store_plans 뷰 컬럼 속성
컬럼명 속성 설명
userid oid OID of user who executed the statement
dbid oid OID of database in which the statement was executed
queryid bigint Core-generated query ID. If compute_query_id is set to "no", pg_store_plan is silently disabled. This is usable as the join key with pg_stat_statements.
planid bigint Plan hash code, computed from the normalized plan representation.
plan text Text of a representative plan. The format is specified by the configuration parameter pg_store_plans.plan_format.
calls bigint Number of times executed
total_time double precision Total time spent in the statement using the plan, in milliseconds
rows bigint Total number of rows retrieved or affected by the statement using the plan
shared_blks_hit bigint Total number of shared block cache hits by the statement using the plan
shared_blks_read bigint Total number of shared blocks read by the statement using the plan
shared_blks_dirtied bigint Total number of shared blocks dirtied by the statement using the plan
shared_blks_written bigint Total number of shared blocks written by the statement using the plan
local_blks_hit bigint Total number of local block cache hits by the statement using the plan
local_blks_read bigint Total number of local blocks read by the statement using the plan
local_blks_dirtied bigint Total number of local blocks dirtied by the statement using the plan
local_blks_written bigint Total number of local blocks written by the statement using the plan
temp_blks_read bigint Total number of temp blocks read by the statement using the plan
temp_blks_written bigint Total number of temp blocks written by the statement using the plan
blk_read_time double precision Total time the statement using the plan spent reading blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)
blk_write_time double precision Total time the statement using the plan spent writing blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)
temp_blk_read_time double precision Total time the statement using the plan spent reading temporary file blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)
temp_blk_write_time double precision Total time the statement using the plan spent writing temporary file blocks, in milliseconds (if track_io_timing is enabled, otherwise zero)
first_call timestamp with time zone Timestamp for the least recently call of the query using this plan.
last_call timestamp with time zone Timestamp for the most recently call of the query using this plan.

 

  • pg_store_plans 관련 파라미터
이름 기본값 설명
pg_store_plans.log_analyze off Use EXPLAIN ANALYZE for plan logging.
pg_store_plans.log_buffers off Log buffer usage.
pg_store_plans.log_timing on Log timings.
pg_store_plans.log_triggers off Log trigger trace.
pg_store_plans.log_verbose off Set VERBOSE for EXPLAIN on logging.
pg_store_plans.max 1000 Sets the maximum number of plans tracked by pg_store_plans.
pg_store_plans.max_plan_length 5000 Sets the maximum length of plans stored by pg_store_plans.
pg_store_plans.min_duration 0 Minimum duration to record plan in milliseconds.
pg_store_plans.plan_format text Selects which format to be appied for plan representation in pg_store_plans.
pg_store_plans.plan_storage file Selects where to store plan texts.
pg_store_plans.save on Save pg_store_plans statistics across server shutdowns.
pg_store_plans.track top Selects which plans are tracked by pg_store_plans.

 

 

댓글