pg_stat_statements
모듈은 서버에서 실행 되었던
쿼리들에 대한 실행계획과 실행 통계 정보를 보여준다.
이 모듈을 사용하려면, 먼저 shared_preload_libraries
서버 환경 설정 값에 pg_stat_statements
값이 추가 되어 있어야한다.
이 모듈은 추가적인 공유 메모리를 사용하기 때문에,
이렇게 서버 환경 설정도 바꾸어야 하며,
이것이 적용 하기 위해서는 서버도 다시 실행 해야한다. 물론 이 모듈을 더 이상
사용하지 않아 추가적인 공유 메모리 사용을 하지 않으려고 할 때도 마찮가지다.
pg_stat_statements
모듈이 로드되면,
이 때부터 해당 서버의 모든 데이터베이스에서 일어라는 쿼리 통계가
수집된다. 하지만, 이 통계를 보는 pg_stat_statements
뷰,
통계를 비우는 pg_stat_statements_reset
함수,
통계를 보는 pg_stat_statements
함수들은
각 데이터베이스 별로 지정해야 한다. 이 작업은 해당 데이터베이스로 접속해서
CREATE EXTENSION pg_stat_statements
명령을 이용하면 된다.
pg_stat_statements
뷰
이 모듈로 제공하는 쿼리 실행 통계 정보는 pg_stat_statements
이름의
뷰로 제공된다. 이 뷰는 하나의 로우가 하나의 식별되는 쿼리를 뜻하며, 부가적으로
그 쿼리가 실행되었던 데이터베이스 ID, 사용자 ID등을 포함 하고 있다. (이 뷰에서
제공하고 있는 최대 쿼리 개수는 이 모듈 환경 설정값에 따라 결정 된다.)
표 F.21 표에서는 이 뷰의 각 칼럼에 대한 설명을
하고 있다.
표 F.21. pg_stat_statements
칼럼들
칼럼명 자료형 설명 |
---|
해당 쿼리를 실행 했던 사용자 OID |
해당 쿼리가 실행 되었던 데이터베이스 OID |
해당 쿼리 통계 작업을 위한 내부용 계산된 해시 코드 |
해당 쿼리의 구문 내용 |
해당 쿼리의 실행 계획을 짰던 총 수
( |
해당 쿼리의 실행 계획을 짜는데 쓴 총 시간, 단위는 밀리세컨드
( |
해당 쿼리의 실행 계획을 짜는데 쓴 시간 중 제일 짧은 시간, 단위는 밀리세컨드
( |
해당 쿼리의 실행 계획을 짜는데 쓴 시간 중 제일 긴 시간, 단위는 밀리세컨드
( |
해당 쿼리의 실행 계획을 짜는데 쓴 평균 시간, 단위는 밀리세컨드
Mean time spent planning the statement, in milliseconds
( |
해당 쿼리가 실행 계획 짜는데 쓴 시간의 표준 편차, 단위는 밀리세컨드
( |
해당 쿼리 총 실행 회수 |
해당 쿼리 실행 시간의 총 누적 시간, 단위는 밀리세컨드 |
해당 쿼리 실행 시간 중 제일 작은 값, 단위는 밀리세컨드 |
해당 쿼리 실행 시간 중 제일 큰 값, 단위는 밀리세컨드 |
해당 쿼리의 평균 실행 시간, 단위는 밀리세컨드 |
해당 쿼리를 실행하는데 걸린 시간의 표준 편차, 단위는 밀리세컨드 |
해당 쿼리로 출력되거나 영향받은 총 로우 수 |
해당 쿼리가 공유 블록 캐시를 히트한 총 수 |
해당 쿼리로 읽은 공유 블록 총 수 |
해당 쿼리로 생긴 더티 공유 블록 총 수 |
해당 쿼리로 쓴 공유 블록 총 수 |
해당 쿼리가 로컬 블록 캐시를 히트한 총 수 |
해당 쿼리로 읽은 로컬 블록 총 수 |
해당 쿼리로 생긴 더티 로컬 블록 총 수 |
해당 쿼리로 쓴 로컬 블록 총 수 |
해당 쿼리로 읽은 임시 블록 총 수 |
해당 쿼리로 쓴 임시 블록 총 수 |
해당 쿼리가 블록 읽기에 쓴 총 시간, 단위는 밀리세컨드 (track_io_timing 설정값이 on인 경우, off면 0) |
해당 쿼리가 블록 쓰기에 쓴 총 시간, 단위는 밀리세컨드 (track_io_timing 설정값이 on인 경우, off면 0) |
해당 쿼리로 만들어진 WAL 레코드 총 수 |
해당 쿼리로 만들어진 WAL full page 이미지 총 수 |
해당 쿼리로 만들어진 WAL 총 크기, 단위는 바이트 |
보안 문제로, 슈퍼 유저와 pg_read_all_stats
롤 소속
사용자만 다른 사용자가 실행한
queryid
나 쿼리 내용을를 볼 수 있다. 한편,
그 외 통계 정보는 일반 사용자도 볼 수 있다. (물론 해당 데이터베이스
이 모듈의 확장 기능이 설치 되어 있는 경우를 말한다)
실행계획을 짤 수 있는 쿼리들(SELECT
, INSERT
,
UPDATE
, DELETE
구문들)은 그 실행계획이 같은
쿼리들에 대해서는 그 조건 값들이 다르더라도 같은 쿼리로 취급한다.
즉, 쿼리에서 사용한 글자 그대로의 상수 값들만 달라서 실질적으로
그 실행계획이 같은 것들은 pg_stat_statements
뷰에서는
하나의 쿼리로 취급한다. 하지만, 앞에서 설명한 쿼리들이 아닌
객체 정의 명령들은 상수 값들과 관계 없이 무조건 개별 쿼리로 취급한다.
pg_stat_statements
뷰에서 상수 부분에
$1
형태로 표시된 것이 앞에서 설명한 동일 쿼리로 취급하기 위한
상수 값의 변경된 값이다.
이렇게 변경된 쿼리 문이 다음에도 사용된다면, 그 queryid
로
같이 취급한다.
또한 몇몇 상황에서는 실제 쿼리가 다른 쿼리임에도 불구하고,
pg_stat_statements
뷰에서 같은 항목의 쿼리로 취급되기도 한다.
일반적으로 이런 경우는 구문적으로 보면 동일 쿼리이지만, 그 해시 값이 약간 다른 경우,
같은 쿼리로 취급한다. (하지만, 이런 통합작업은 사용자나 데이터베이스가 다른 상황에서는
일어나지 않는다.)
이 해시 값 비교 방식은 쿼리 구문분석 다음에 처리 되기 때문에,
위와 반대로 동일 쿼리임에도 불구하고, search_path
와 같은
설정값이 다르기 때문에 다른 쿼리로 처리하는 경우도 발생할 수 있다.
Consumers of pg_stat_statements
may wish to use
queryid
(perhaps in combination with
dbid
and userid
) as a more stable
and reliable identifier for each entry than its query text.
However, it is important to understand that there are only limited
guarantees around the stability of the queryid
hash
value. Since the identifier is derived from the
post-parse-analysis tree, its value is a function of, among other
things, the internal object identifiers appearing in this representation.
This has some counterintuitive implications. For example,
pg_stat_statements
will consider two apparently-identical
queries to be distinct, if they reference a table that was dropped
and recreated between the executions of the two queries.
The hashing process is also sensitive to differences in
machine architecture and other facets of the platform.
Furthermore, it is not safe to assume that queryid
will be stable across major versions of PostgreSQL.
As a rule of thumb, queryid
values can be assumed to be
stable and comparable only so long as the underlying server version and
catalog metadata details stay exactly the same. Two servers
participating in replication based on physical WAL replay can be expected
to have identical queryid
values for the same query.
However, logical replication schemes do not promise to keep replicas
identical in all relevant details, so queryid
will
not be a useful identifier for accumulating costs across a set of logical
replicas. If in doubt, direct testing is recommended.
The parameter symbols used to replace constants in
representative query texts start from the next number after the
highest $
n
parameter in the original query
text, or $1
if there was none. It's worth noting that in
some cases there may be hidden parameter symbols that affect this
numbering. For example, PL/pgSQL uses hidden parameter
symbols to insert values of function local variables into queries, so that
a PL/pgSQL statement like SELECT i + 1 INTO j
would have representative text like SELECT i + $2
.
The representative query texts are kept in an external disk file, and do
not consume shared memory. Therefore, even very lengthy query texts can
be stored successfully. However, if many long query texts are
accumulated, the external file might grow unmanageably large. As a
recovery method if that happens, pg_stat_statements
may
choose to discard the query texts, whereupon all existing entries in
the pg_stat_statements
view will show
null query
fields, though the statistics associated with
each queryid
are preserved. If this happens, consider
reducing pg_stat_statements.max
to prevent
recurrences.
plans
and calls
aren't
always expected to match because planning and execution statistics are
updated at their respective end phase, and only for successful operations.
For example, if a statement is successfully planned but fails during
the execution phase, only its planning statistics will be updated.
If planning is skipped because a cached plan is used, only its execution
statistics will be updated.
pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint) returns void
pg_stat_statements_reset
discards statistics
gathered so far by pg_stat_statements
corresponding
to the specified userid
, dbid
and queryid
. If any of the parameters are not
specified, the default value 0
(invalid) is used for
each of them and the statistics that match with other parameters will be
reset. If no parameter is specified or all the specified parameters are
0
(invalid), it will discard all statistics. By
default, this function can only be executed by superusers. Access may be
granted to others using GRANT
.
pg_stat_statements(showtext boolean) returns setof record
The pg_stat_statements
view is defined in
terms of a function also named pg_stat_statements
.
It is possible for clients to call
the pg_stat_statements
function directly, and by
specifying showtext := false
have query text be
omitted (that is, the OUT
argument that corresponds
to the view's query
column will return nulls). This
feature is intended to support external tools that might wish to avoid
the overhead of repeatedly retrieving query texts of indeterminate
length. Such tools can instead cache the first query text observed
for each entry themselves, since that is
all pg_stat_statements
itself does, and then retrieve
query texts only as needed. Since the server stores query texts in a
file, this approach may reduce physical I/O for repeated examination
of the pg_stat_statements
data.
pg_stat_statements.max
(integer
)
pg_stat_statements.max
값은 이 모듈에서
처리할 수 있는 최대 쿼리 수를 지정한다.
pg_stat_statements
뷰에 보일 최대 로우 수를 뜻한다.
If more distinct statements than that are observed,
information about the least-executed statements is discarded.
초기값은 1000. 이 값은 서버 기동할 때만 지정할 수 있다.
pg_stat_statements.track
(enum
)
pg_stat_statements.track
설정은
수집할 쿼리문의 사용빈도에 따른 쿼리문 사용 통계 정보 수집범위를 지정한다.
top
으로 지정하면, 자주 사용하는 쿼리들을 대상으로 하고,
all
로 지정하면 모든 쿼리들을 대상으로,
none
으로 지정하면, 아무 쿼리도 수집하지 않는다.
초기값은 top
이다.
이 값은 슈퍼유저만 바꿀 수 있다.
pg_stat_statements.track_utility
(boolean
)
pg_stat_statements.track_utility
설정은
SELECT
, INSERT
, UPDATE
, DELETE
구문 외 다른 구문들도 수집 대상으로 할 것인지를 지정한다.
초기값은 on
이다.
이 값은 슈퍼유저만 바꿀 수 있다.
pg_stat_statements.track_planning
(boolean
)
pg_stat_statements.track_planning
controls whether
planning operations and duration are tracked by the module.
Enabling this parameter may incur a noticeable performance penalty,
especially when a fewer kinds of queries are executed on many
concurrent connections.
The default value is off
.
Only superusers can change this setting.
pg_stat_statements.save
(boolean
)
pg_stat_statements.save
설정은 서버가 중지 되고,
재실행 되었을 때, 마지막 중지 시점의 쿼리문 통계 정보를
저장할 것인지를 지정한다.
off
로 설정하면, 서버가 재실행될 때 항상
모든 쿼리문에 대한 통계정보를 초기화 한다.
초기값은 on
이다.
이 환경설정 값은 postgresql.conf
파일에서 지정하거나
서버 실행 명령행 옵션에서만 지정할 수 있다.
이 모듈은 pg_stat_statements.max
*
track_activity_query_size 바이트만큼의
공유 메모리를 추가로 필요로 한다.
참고할 사항은 pg_stat_statements.track
값을
none
으로 지정했다 하더라도 앞의 계산식 만큼의
공유 메모리는 항상 사용한다는 점이다.
postgresql.conf
파일에 이 모듈을 사용할 때의 기본 내용은
다음과 같다:
# postgresql.conf shared_preload_libraries = 'pg_stat_statements' pg_stat_statements.max = 10000 pg_stat_statements.track = all
bench=# SELECT pg_stat_statements_reset(); $ pgbench -i bench $ pgbench -c10 -t300 bench bench=# \x bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5; -[ RECORD 1 ]---+-------------------------------------------------------------------- query | UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2 calls | 3000 total_exec_time | 25565.855387 rows | 3000 hit_percent | 100.0000000000000000 -[ RECORD 2 ]---+-------------------------------------------------------------------- query | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2 calls | 3000 total_exec_time | 20756.669379 rows | 3000 hit_percent | 100.0000000000000000 -[ RECORD 3 ]---+-------------------------------------------------------------------- query | copy pgbench_accounts from stdin calls | 1 total_exec_time | 291.865911 rows | 100000 hit_percent | 100.0000000000000000 -[ RECORD 4 ]---+-------------------------------------------------------------------- query | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2 calls | 3000 total_exec_time | 271.232977 rows | 3000 hit_percent | 98.8454011741682975 -[ RECORD 5 ]---+-------------------------------------------------------------------- query | alter table pgbench_accounts add primary key (aid) calls | 1 total_exec_time | 160.588563 rows | 0 hit_percent | 100.0000000000000000 bench=# SELECT pg_stat_statements_reset(0,0,s.queryid) FROM pg_stat_statements AS s WHERE s.query = 'UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2'; bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5; -[ RECORD 1 ]---+-------------------------------------------------------------------- query | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2 calls | 3000 total_exec_time | 20756.669379 rows | 3000 hit_percent | 100.0000000000000000 -[ RECORD 2 ]---+-------------------------------------------------------------------- query | copy pgbench_accounts from stdin calls | 1 total_exec_time | 291.865911 rows | 100000 hit_percent | 100.0000000000000000 -[ RECORD 3 ]---+-------------------------------------------------------------------- query | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2 calls | 3000 total_exec_time | 271.232977 rows | 3000 hit_percent | 98.8454011741682975 -[ RECORD 4 ]---+-------------------------------------------------------------------- query | alter table pgbench_accounts add primary key (aid) calls | 1 total_exec_time | 160.588563 rows | 0 hit_percent | 100.0000000000000000 -[ RECORD 5 ]---+-------------------------------------------------------------------- query | vacuum analyze pgbench_accounts calls | 1 total_exec_time | 136.448116 rows | 0 hit_percent | 99.9201915403032721 bench=# SELECT pg_stat_statements_reset(0,0,0); bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5; -[ RECORD 1 ]---+----------------------------------------------------------------------------- query | SELECT pg_stat_statements_reset(0,0,0) calls | 1 total_exec_time | 0.189497 rows | 1 hit_percent | -[ RECORD 2 ]---+----------------------------------------------------------------------------- query | SELECT query, calls, total_exec_time, rows, $1 * shared_blks_hit / + | nullif(shared_blks_hit + shared_blks_read, $2) AS hit_percent+ | FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT $3 calls | 0 total_exec_time | 0 rows | 0 hit_percent |
Takahiro Itagaki <itagaki.takahiro@oss.ntt.co.jp>
.
Query normalization added by Peter Geoghegan <peter@2ndquadrant.com>
.