F.29. pg_stat_statements

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 명령을 이용하면 된다.

F.29.1. pg_stat_statements

이 모듈로 제공하는 쿼리 실행 통계 정보는 pg_stat_statements 이름의 뷰로 제공된다. 이 뷰는 하나의 로우가 하나의 식별되는 쿼리를 뜻하며, 부가적으로 그 쿼리가 실행되었던 데이터베이스 ID, 사용자 ID등을 포함 하고 있다. (이 뷰에서 제공하고 있는 최대 쿼리 개수는 이 모듈 환경 설정값에 따라 결정 된다.) 표 F-22 표에서는 이 뷰의 각 칼럼에 대한 설명을 하고 있다.

표 F-22. pg_stat_statements 칼럼들

칼럼명자료형참조설명
useridoidpg_authid.oid해당 쿼리를 실행했던 사용자의 OID
dbidoidpg_database.oid해당 쿼리를 실행했던 데이터베이스 OID
querytext 해당 쿼리 내용(track_activity_query_size 값으로 지정한 크기만큼만 저장됨)
callsbigint 실행 회수
total_timedouble precision 밀리세컨드 단위 총 실행 시간
min_timedouble precision 해당 구문 최소 실행 시간, 밀리초
max_timedouble precision 해당 구문 최대 실행 시간, 밀리초
mean_timedouble precision 해당 구문 평균 실행 시간, 밀리초
stddev_timedouble precision 해당 구문 실행 시간의 표준 편차, 밀리초
rowsbigint 해당 쿼리로 출력한 또는 영향 받는 총 로우 개수
shared_blks_hitbigint Total number of shared block cache hits by the statement
shared_blks_readbigint Total number of shared blocks read by the statement
shared_blks_dirtiedbigint Total number of shared blocks dirtied by the statement
shared_blks_writtenbigint Total number of shared blocks written by the statement
local_blks_hitbigint Total number of local block cache hits by the statement
local_blks_readbigint Total number of local blocks read by the statement
local_blks_dirtiedbigint Total number of local blocks dirtied by the statement
local_blks_writtenbigint Total number of local blocks written by the statement
temp_blks_readbigint Total number of temp blocks read by the statement
temp_blks_writtenbigint Total number of temp blocks written by the statement
blk_read_timedouble precision  블록을 디스크에서 읽는데 소비한 총 시간, 밀리세컨드 (track_io_timing 값이 on 상태여야 함, 그렇지 않으면, 0)
blk_write_timedouble precision  블록을 디스크로 쓰는데 소비한 총 시간, 밀리세컨드 (track_io_timing 값이 on 상태여야 함, 그렇지 않으면, 0)

보안 문제로, 슈퍼유저가 아닌 일반 사용자는 다른 사용자의 쿼리 내용과 queryid를 볼 수 없지만, 그것들의 통계 정보는 볼 수 있다. (물론 해당 데이터베이스 이 모듈의 확장 기능이 설치 되어 있는 경우를 말한다)

실행계획을 짤 수 있는 쿼리들(SELECT, INSERT, UPDATE, DELETE 구문들)은 그 실행계획이 같은 쿼리들에 대해서는 그 조건 값들이 다르더라도 같은 쿼리로 취급한다. 즉, 쿼리에서 사용한 글자 그대로의 상수 값들만 달라서 실질적으로 그 실행계획이 같은 것들은 pg_stat_statements 뷰에서는 하나의 쿼리로 취급한다. 하지만, 앞에서 설명한 쿼리들이 아닌 객체 정의 명령들은 상수 값들과 관계 없이 무조건 개별 쿼리로 취급한다.

pg_stat_statements 뷰에서 상수 부분에 ? 표시된 것이 앞에서 설명한 동일 쿼리로 취급하기 위한 상수 값의 변경된 값이다. 첫번째 쿼리는 pg_stat_statements 뷰의 항목과 관련된 특정 해시 값을 가진다. 그래서 다음 실행되는 쿼리가 이렇게 변환된 것과 같은 해시 값을 가진다면, 같은 쿼리로 간주한다. ( - 다음 문장 의역임) The rest of the query text is that of the first query that had the particular hash value associated with the pg_stat_statements entry.

또한 몇몇 상황에서는 실제 쿼리가 다른 쿼리임에도 불구하고, 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 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.

F.29.2. 함수들

pg_stat_statements_reset() returns void

pg_stat_statements_reset 함수는 pg_stat_statements 모듈에서 사용하기 위해 수집된 모든 정보를 삭제한다. 기본적으로 이 작업은 슈퍼유저만 실행 할 수 있다.

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.

F.29.3. 환경설정 매개변수들

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.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

F.29.4. 예제 출력

bench=# SELECT pg_stat_statements_reset();

$ pgbench -i bench
$ pgbench -c10 -t300 bench

bench=# \x
bench=# SELECT query, calls, total_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_time DESC LIMIT 5;
-[ RECORD 1 ]---------------------------------------------------------------------
query       | UPDATE pgbench_branches SET bbalance = bbalance + ? WHERE bid = ?;
calls       | 3000
total_time  | 9609.00100000002
rows        | 2836
hit_percent | 99.9778970000200936
-[ RECORD 2 ]---------------------------------------------------------------------
query       | UPDATE pgbench_tellers SET tbalance = tbalance + ? WHERE tid = ?;
calls       | 3000
total_time  | 8015.156
rows        | 2990
hit_percent | 99.9731126579631345
-[ RECORD 3 ]---------------------------------------------------------------------
query       | copy pgbench_accounts from stdin
calls       | 1
total_time  | 310.624
rows        | 100000
hit_percent | 0.30395136778115501520
-[ RECORD 4 ]---------------------------------------------------------------------
query       | UPDATE pgbench_accounts SET abalance = abalance + ? WHERE aid = ?;
calls       | 3000
total_time  | 271.741999999997
rows        | 3000
hit_percent | 93.7968855088209426
-[ RECORD 5 ]---------------------------------------------------------------------
query       | alter table pgbench_accounts add primary key (aid)
calls       | 1
total_time  | 81.42
rows        | 0
hit_percent | 34.4947735191637631

F.29.5. 만든이

Takahiro Itagaki . Query normalization added by Peter Geoghegan .