PostgreSQL์šฉ ASH ์•„๋‚ ๋กœ๊ทธ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋Š” ์‹œ๋„

๋ฌธ์ œ ์„ฑ๋ช…

PostgreSQL ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™”ํ•˜๋ ค๋ฉด ํ™œ๋™ ๋‚ด์—ญ, ํŠนํžˆ ๋Œ€๊ธฐ, ์ž ๊ธˆ, ํ…Œ์ด๋ธ” ํ†ต๊ณ„๋ฅผ ๋ถ„์„ํ•˜๋Š” ๋Šฅ๋ ฅ์ด ๋งค์šฐ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด์šฉ ๊ฐ€๋Šฅํ•œ ๊ธฐํšŒ

๊ธฐ๋ก ์›Œํฌ๋กœ๋“œ ๋ถ„์„ ๋„๊ตฌ ๋˜๋Š” "AWR for Postgres": ๋งค์šฐ ํฅ๋ฏธ๋กœ์šด ํ•ด๊ฒฐ์ฑ…์ด์ง€๋งŒ pg_stat_activity ๋ฐ pg_locks์˜ ๊ธฐ๋ก์€ ์—†์Šต๋‹ˆ๋‹ค.

pgsentinel ํ™•์žฅ :
ยซ์ถ•์ ๋œ ๋ชจ๋“  ์ •๋ณด๋Š” RAM์—๋งŒ ์ €์žฅ๋˜๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„๋Ÿ‰์€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ €์žฅ๋œ ๋ ˆ์ฝ”๋“œ ์ˆ˜์— ๋”ฐ๋ผ ๊ทœ์ œ๋ฉ๋‹ˆ๋‹ค.

queryid ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค - pg_stat_statements ํ™•์žฅ์˜ ๋™์ผํ•œ queryid์ž…๋‹ˆ๋‹ค(์‚ฌ์ „ ์„ค์น˜ ํ•„์š”).ยซ

๋ฌผ๋ก  ๋„์›€์ด ๋งŽ์ด ๋˜๊ฒ ์ง€๋งŒ ๊ฐ€์žฅ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์€ ์ฒซ ๋ฒˆ์งธ ํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค.โ€์ถ•์ ๋œ ๋ชจ๋“  ์ •๋ณด๋Š” RAM์—๋งŒ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ", ์ฆ‰. ๋Œ€์ƒ ๊ธฐ๋ฐ˜์— ์˜ํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž ๊ธˆ ๊ธฐ๋ก ๋ฐ ํ…Œ์ด๋ธ” ํ†ต๊ณ„๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ €๊ฒƒ๋“ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์†”๋ฃจ์…˜์€ ๋ถˆ์™„์ „ํ•ฉ๋‹ˆ๋‹ค.์•„์ง ์„ค์น˜๋ฅผ ์œ„ํ•ด ๊ธฐ์„ฑํ’ˆ ํŒจํ‚ค์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์†Œ์Šค๋ฅผ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ง์ ‘ ์กฐ๋ฆฝํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๋จผ์ € ์„œ๋ฒ„์— "devel" ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ณ  PATH ๋ณ€์ˆ˜์— pg_config ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.".

์ผ๋ฐ˜์ ์œผ๋กœ ์†Œ๋ž€์ด ๋งŽ์œผ๋ฉฐ ์‹ฌ๊ฐํ•œ ํ”„๋กœ๋•์…˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„๋กœ ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋‹ค์‹œ ์šฐ๋ฆฌ ์ž์‹ ์˜ ๊ฒƒ์„ ์ƒ๊ฐํ•ด ๋‚ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ฒฝ๊ณ 

๋ถ„๋Ÿ‰์ด ๋งŽ๊ณ  ํ…Œ์ŠคํŠธ ๊ธฐ๊ฐ„์ด ๋ถˆ์™„์ „ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ธฐ์‚ฌ๋Š” ์ผ๋ จ์˜ ๋…ผ๋ฌธ ๋ฐ ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๋ณด๋‹ค๋Š” ์ฃผ๋กœ ์ •๋ณด ์ œ๊ณต ์„ฑ๊ฒฉ์„ ๋ ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋” ์ž์„ธํ•œ ์ž๋ฃŒ๋Š” ๋‚˜์ค‘์— ๋ถ€๋ถ„์ ์œผ๋กœ ์ค€๋น„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์†”๋ฃจ์…˜์— ๋Œ€ํ•œ ์ดˆ์•ˆ ์š”๊ตฌ ์‚ฌํ•ญ

๋‹ค์Œ์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋ฅผ ๊ฐœ๋ฐœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

pg_stat_activity ๋ณด๊ธฐ ๊ธฐ๋ก
pg_locks ๋ทฐ๋ฅผ ์‚ฌ์šฉํ•œ ์„ธ์…˜ ์ž ๊ธˆ ๊ธฐ๋ก

์†”๋ฃจ์…˜ ์š”๊ตฌ์‚ฌํ•ญโ€“ ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์˜ํ–ฅ์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์ƒ๊ฐโ€“ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ์—์ด์ „ํŠธ๋Š” ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์•„๋‹Œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ systemd ์„œ๋น„์Šค๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ์˜ˆ, ์ผ๋ถ€ ๋ฐ์ดํ„ฐ ์†์‹ค์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ด๋Š” ๋ณด๊ณ ์— ์ค‘์š”ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋ฉ”๋ชจ๋ฆฌ ๋ฐ ๋””์Šคํฌ ๊ณต๊ฐ„ ์ธก๋ฉด์—์„œ ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฐ๊ฒฐ ํ’€์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ํ”„๋กœ์„ธ์Šค์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์€ ์ตœ์†Œํ™”๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ๋‹จ๊ณ„

1. ์„œ๋น„์Šค ํ…Œ์ด๋ธ”

์‚ฌ์šฉ๋˜๋Š” ์ฃผ์š” ํ…Œ์ด๋ธ”์˜ ๋ถ„์„์„ ๋ณต์žกํ•˜๊ฒŒ ํ•˜์ง€ ์•Š๋„๋ก ํ…Œ์ด๋ธ”์„ ์ €์žฅํ•˜๋Š” ๋ฐ ๋ณ„๋„์˜ ์Šคํ‚ค๋งˆ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

DROP SCHEMA IF EXISTS activity_hist ;
CREATE SCHEMA activity_hist AUTHORIZATION monitor ;

์ค‘์š”: ์Šคํ‚ค๋งˆ๋Š” ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ์•„๋‹Œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

pg_stat_activity ๋ณด๊ธฐ ๊ธฐ๋ก

pg_stat_activity ๋ทฐ์˜ ํ˜„์žฌ ์Šค๋ƒ…์ƒท์„ ์ €์žฅํ•˜๋Š” ๋ฐ ํ…Œ์ด๋ธ”์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Activity_hist.history_pg_stat_activity:

--ACTIVITY_HIST.HISTORY_PG_STAT_ACTIVITY
DROP TABLE IF EXISTS activity_hist.history_pg_stat_activity;
CREATE TABLE activity_hist.history_pg_stat_activity
(
  timepoint timestamp without time zone ,
  datid             oid  , 
  datname           name ,
  pid               integer,
  usesysid          oid    ,
  usename           name   ,
  application_name  text   ,
  client_addr       inet   ,
  client_hostname   text   ,
  client_port       integer,
  backend_start     timestamp with time zone ,
  xact_start        timestamp with time zone ,
  query_start       timestamp with time zone ,
  state_change      timestamp with time zone ,
  wait_event_type   text ,                     
  wait_event        text ,                   
  state             text ,                  
  backend_xid       xid  ,                 
  backend_xmin      xid  ,                
  query             text ,               
  backend_type      text ,  
  queryid           bigint
);

์‚ฝ์ž… ์†๋„๋ฅผ ๋†’์ด๋ ค๋ฉด ์ƒ‰์ธ์ด๋‚˜ ์ œํ•œ์ด ์—†์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ก ์ž์ฒด๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„ํ• ๋œ ํ…Œ์ด๋ธ”์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Activity_hist.archive_pg_stat_activity:

DROP TABLE IF EXISTS activity_hist.archive_pg_stat_activity;
CREATE TABLE activity_hist.archive_pg_stat_activity
(
  timepoint timestamp without time zone ,
  datid             oid  , 
  datname           name ,
  pid               integer,
  usesysid          oid    ,
  usename           name   ,
  application_name  text   ,
  client_addr       inet   ,
  client_hostname   text   ,
  client_port       integer,
  backend_start     timestamp with time zone ,
  xact_start        timestamp with time zone ,
  query_start       timestamp with time zone ,
  state_change      timestamp with time zone ,
  wait_event_type   text ,                     
  wait_event        text ,                   
  state             text ,                  
  backend_xid       xid  ,                 
  backend_xmin      xid  ,                
  query             text ,               
  backend_type      text ,
  queryid           bigint
)
PARTITION BY RANGE (timepoint);

์ด ๊ฒฝ์šฐ ์‚ฝ์ž… ์†๋„์— ๋Œ€ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์—†์œผ๋ฏ€๋กœ ๋ณด๊ณ ์„œ ์ƒ์„ฑ ์†๋„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ์ƒ‰์ธ์ด ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์„ธ์…˜ ์ฐจ๋‹จ ๊ธฐ๋ก

ํ…Œ์ด๋ธ”์€ ์„ธ์…˜ ์ž ๊ธˆ์˜ ํ˜„์žฌ ์Šค๋ƒ…์ƒท์„ ์ €์žฅํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Activity_hist.history_locking :

--ACTIVITY_HIST.HISTORY_LOCKING
DROP TABLE IF EXISTS activity_hist.history_locking;
CREATE TABLE activity_hist.history_locking
(
	timepoint timestamp without time zone ,
	locktype text ,
	relation oid ,
	mode text ,
	tid xid ,
	vtid text ,
	pid integer ,
	blocking_pids integer[] ,
	granted boolean
);

๋˜ํ•œ ์‚ฝ์ž… ์†๋„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ƒ‰์ธ์ด๋‚˜ ์ œํ•œ ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ก ์ž์ฒด๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„ํ• ๋œ ํ…Œ์ด๋ธ”์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

ํ™œ๋™_hist.archive_locking:

DROP TABLE IF EXISTS activity_hist.archive_locking;
CREATE TABLE activity_hist.archive_locking
(
	timepoint timestamp without time zone ,
	locktype text ,
	relation oid ,
	mode text ,
	tid xid ,
	vtid text ,
	pid integer ,
	blocking_pids integer[] ,
	granted boolean	
)
PARTITION BY RANGE (timepoint);

์ด ๊ฒฝ์šฐ ์‚ฝ์ž… ์†๋„์— ๋Œ€ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์ด ์—†์œผ๋ฏ€๋กœ ๋ณด๊ณ ์„œ ์ƒ์„ฑ ์†๋„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ์ƒ‰์ธ์ด ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

2.ํ˜„์žฌ ์ด๋ ฅ ์ž‘์„ฑ

๋ทฐ ์Šค๋ƒ…์ƒท์„ ์ง์ ‘ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•ด plpgsql ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” bash ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

get_current_activity.sh

#!/bin/bash
#########################################################
#get_current_activity.sh

ERROR_FILE='/home/demon/get_current_activity'$(date +%Y%m%d-)'T'$(date +%H)$(date +%M)$(date +%S)
host=$1
s_name=$2
s_pass=$3

psql  -A -t -q -v ON_ERROR_STOP=1 -c "SELECT activity_hist.get_current_activity( '$host' , '$s_name' , '$s_pass' )" >/dev/null 2>$ERROR_FILE

line_count=`cat $ERROR_FILE | wc -l`
if [[ $line_count != '0' ]];
then
    rm -f /home/demon/*.err >/dev/null 2>/dev/null
	cp $ERROR_FILE $ERROR_FILE'.err' >/dev/null 2>/dev/null  
fi
rm $ERROR_FILE >/dev/null 2>/dev/null
exit 0

plpgsql dblink ํ•จ์ˆ˜๋Š” ๋Œ€์ƒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ทฐ์— ์•ก์„ธ์Šคํ•˜๊ณ  ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์„œ๋น„์Šค ํ…Œ์ด๋ธ”์— ํ–‰์„ ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

get_current_activity.sql

CREATE OR REPLACE FUNCTION activity_hist.get_current_activity( current_host text , current_s_name text , current_s_pass text ) RETURNS BOOLEAN AS $$
DECLARE 
  database_rec record;
  dblink_str text ;
BEGIN   

	EXECUTE 'SELECT dblink_connect(''LINK1'',''host='||current_host||' port=5432 dbname=postgres'||
	                                         ' user='||current_s_name||' password='||current_s_pass|| ' '')';



--------------------------------------------------------------------
--GET pg_stat_activity stats
	INSERT INTO activity_hist.history_pg_stat_activity
	(
		SELECT * FROM dblink('LINK1',
			'SELECT 
			now() , 
			datid             , 
			datname           ,
			pid               ,
			usesysid              ,
			usename              ,
			application_name     ,
			client_addr          ,
			client_hostname      ,
			client_port       ,
			backend_start         ,
			xact_start            ,
			query_start           ,
			state_change          ,
			wait_event_type    ,                     
			wait_event         ,                   
			state              ,                  
			backend_xid         ,                 
			backend_xmin        ,                
			query              ,               
			backend_type   			
		FROM pg_stat_activity
		') 
		AS t (
		    timepoint 		  timestamp without time zone ,			
			datid             oid  , 
			datname           name ,
			pid               integer,
			usesysid          oid    ,
			usename           name   ,
			application_name  text   ,
			client_addr       inet   ,
			client_hostname   text   ,
			client_port       integer,
			backend_start     timestamp with time zone ,
			xact_start        timestamp with time zone ,
			query_start       timestamp with time zone ,
			state_change      timestamp with time zone ,
			wait_event_type   text ,                     
			wait_event        text ,                   
			state             text ,                  
			backend_xid       xid  ,                 
			backend_xmin      xid  ,                
			query             text ,               
			backend_type      text 			
		)
	);

---------------------------------------	
--ACTIVITY_HIST.HISTORY_LOCKING	
	INSERT INTO activity_hist.history_locking
	(
		SELECT * FROM dblink('LINK1',
			'SELECT 
			now() , 
			lock.locktype,
			lock.relation,
			lock.mode,
			lock.transactionid as tid,
			lock.virtualtransaction as vtid,
			lock.pid,
			pg_blocking_pids(lock.pid), 
			lock.granted
			FROM 	pg_catalog.pg_locks lock LEFT JOIN pg_catalog.pg_database db ON db.oid = lock.database
			WHERE NOT lock.pid = pg_backend_pid()	
		') 
		AS t (
			timepoint timestamp without time zone ,
			locktype text ,
			relation oid , 
			mode text ,
			tid xid ,
			vtid text ,
			pid integer ,
			blocking_pids integer[] ,
			granted boolean
		)
	);
	PERFORM dblink_disconnect('LINK1');
	
	RETURN TRUE ;
END
$$ LANGUAGE plpgsql;

๋ทฐ ์Šค๋ƒ…์ƒท์„ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•ด systemd ์„œ๋น„์Šค์™€ ๋‘ ๊ฐœ์˜ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

pg_current_activity.service

# /etc/systemd/system/pg_current_activity.service
[Unit]
Description=Collect history of pg_stat_activity , pg_locks 
Wants=pg_current_activity.timer

[Service]
Type=forking
StartLimitIntervalSec=0
ExecStart=/home/postgres/pgutils/demon/get_current_activity.sh 10.124.70.40 postgres postgres

[Install]
WantedBy=multi-user.target

pg_current_activity.timer

# /etc/systemd/system/pg_current_activity.timer
[Unit]
Description=Run pg_current_activity.sh every 1 second
Requires=pg_current_activity.service

[Timer]
Unit=pg_current_activity.service
OnCalendar=*:*:0/1
AccuracySec=1

[Install]
WantedBy=timers.target

์Šคํฌ๋ฆฝํŠธ์— ๊ถŒํ•œ ํ• ๋‹น:
# chmod 755 pg_current_activity.timer
# chmod 755 pg_current_activity.service

์„œ๋น„์Šค๋ฅผ ์‹œ์ž‘ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
# systemctl daemon-reload
# systemctl start pg_current_activity.service

๋”ฐ๋ผ์„œ ์กฐํšŒ ๊ธฐ๋ก์€ ์ดˆ ๋‹จ์œ„ ์Šค๋ƒ…์ƒท ํ˜•์‹์œผ๋กœ ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋ชจ๋“  ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ๋‘๋ฉด ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๊ฐ€ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ฆ๊ฐ€ํ•˜๊ณ  ์–ด๋Š ์ •๋„ ์ƒ์‚ฐ์ ์ธ ์ž‘์—…์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ๋ณด๊ด€์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

3. ๋ณด๊ด€์ด๋ ฅ

๋ณด๊ด€์—๋Š” ๋ถ„ํ• ๋œ ํ…Œ์ด๋ธ” archive*๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๋งค์‹œ๊ฐ„ ์ƒˆ๋กœ์šด ํŒŒํ‹ฐ์…˜์ด ์ƒ์„ฑ๋˜๊ณ , ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋Š” ๊ธฐ๋ก* ํ…Œ์ด๋ธ”์—์„œ ์ œ๊ฑฐ๋˜๋ฏ€๋กœ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ๊ธฐ๋ก* ํ…Œ์ด๋ธ”์˜ ํฌ๊ธฐ๊ฐ€ ํฌ๊ฒŒ ๋ณ€ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์‚ฝ์ž… ์†๋„๋„ ์ €ํ•˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ƒˆ ์„น์…˜ ์ƒ์„ฑ์€ plpgsql ํ•จ์ˆ˜์ธ Activity_hist.archive_current_activity์— ์˜ํ•ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ์ž‘์—… ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค(archive_pg_stat_activity ํ…Œ์ด๋ธ” ์„น์…˜์˜ ์˜ˆ ์‚ฌ์šฉ).

์ƒˆ ์„น์…˜์„ ๋งŒ๋“ค๊ณ  ์ž‘์„ฑํ•˜์„ธ์š”.

EXECUTE format(
'CREATE TABLE ' || partition_name || 
' PARTITION OF activity_hist.archive_pg_stat_activity FOR VALUES FROM ( %L ) TO ( %L ) ' , 
to_char(date_trunc('year', partition_min_range ),'YYYY')||'-'||
to_char(date_trunc('month', partition_min_range ),'MM')||'-'||
to_char(date_trunc('day', partition_min_range ),'DD')||' '||
to_char(date_trunc('hour', partition_min_range ),'HH24')||':00', 
to_char(date_trunc('year', partition_max_range ),'YYYY')||'-'||
to_char(date_trunc('month', partition_max_range ),'MM')||'-'||
to_char(date_trunc('day', partition_max_range ),'DD')||' '||
to_char(date_trunc('hour', partition_max_range ),'HH24')||':00'
);

INSERT INTO activity_hist.archive_pg_stat_activity
(
	SELECT 	* 
	FROM 	activity_hist.history_pg_stat_activity
	WHERE 	timepoint BETWEEN partition_min_range AND partition_max_range 		
);

์ธ๋ฑ์Šค ์ƒ์„ฑ

EXECUTE format	(
'CREATE INDEX '||index_name||
' ON '||partition_name||' ( wait_event_type , backend_type , timepoint )' 
);

EXECUTE format	('CREATE INDEX '||index_name||
' ON '||partition_name||' ( wait_event_type , backend_type , timepoint , queryid )' 
);

History_pg_stat_activity ํ…Œ์ด๋ธ”์—์„œ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ ์ œ๊ฑฐ

DELETE 
FROM 	activity_hist.history_pg_stat_activity
WHERE 	timepoint < partition_max_range;

๋ฌผ๋ก , ๋•Œ๋•Œ๋กœ ์˜ค๋ž˜๋œ ์„น์…˜์€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๋ณด๊ณ ์„œ

์‚ฌ์‹ค, ์ด ๋ชจ๋“  ์ผ์ด ์™œ ์ผ์–ด๋‚˜๋Š” ๊ฑธ๊นŒ์š”? Oracle์˜ AWR์„ ๋งค์šฐ ๋ชจํ˜ธํ•˜๊ฒŒ ์—ฐ์ƒ์‹œํ‚ค๋Š” ๋ณด๊ณ ์„œ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด.

๋ณด๊ณ ์„œ๋ฅผ ๋ฐ›์œผ๋ ค๋ฉด pg_stat_activity ๋ฐ pg_stat_statements ๋ณด๊ธฐ ์‚ฌ์ด์— ์—ฐ๊ฒฐ์„ ๊ตฌ์ถ•ํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. 'history_pg_stat_activity', 'archive_pg_stat_activity' ํ…Œ์ด๋ธ”์— 'queryid' ์—ด์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ…Œ์ด๋ธ”์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์—ด ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ด ๋ฌธ์„œ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฉฐ ์—ฌ๊ธฐ์— ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. pg_stat_statements + pg_stat_activity + loq_query = pg_ash? .

์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ์ด CPU ์‹œ๊ฐ„

์š”๊ตฌ :

WITH hist AS
(
SELECT 
	aa.query ,aa.queryid ,			
	count(*) * interval '1 second' AS duration 
FROM 	activity_hist.archive_pg_stat_activity aa
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND  pg_stat_history_end+(current_hour_diff * interval '1 hour')  AND backend_type = 'client backend' AND datname != 'postgres' AND	( aa.wait_event_type IS NULL  ) ANDaa.state = 'active'
GROUP BY aa.wait_event_type , aa.wait_event , aa.query ,aa.queryid		
UNION 
SELECT 
	ha.query ,ha.queryid,
	count(*) * interval '1 second' AS duration 
FROM 	activity_hist.history_pg_stat_activity_for_reports ha
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour')  AND 	backend_type = 'client backend' AND datname != 'postgres' AND ( ha.wait_event_type IS NULL  )AND ha.state = 'active'
GROUP BY ha.wait_event_type , ha.wait_event , ha.query ,ha.queryid		
)
SELECT 	query , queryid , SUM( duration ) as duration 
FROM hist
GROUP BY  query , queryid 
ORDER BY 3 DESC

์˜ˆ :

-------------------------------------------------------------------
| TOTAL CPU TIME FOR QUERIES : 07:47:36
+----+----------------------------------------+--------------------
|   #|                                 queryid|            duration
+----+----------------------------------------+--------------------
|   1|                      389015618226997618|            04:28:58
|   2|                                        |            01:07:29
|   3|                     1237430309438971376|            00:59:38
|   4|                     4710212362688288619|            00:50:48
|   5|                       28942442626229688|            00:15:50
|   6|                     9150846928388977274|            00:04:46
|   7|                    -6572922443698419129|            00:00:06
|   8|                                        |            00:00:01
+----+----------------------------------------+--------------------

์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ์ด ๋Œ€๊ธฐ ์‹œ๊ฐ„

์š”๊ตฌ :

WITH hist AS
(
SELECT 
	aa.query ,aa.queryid ,			
	count(*) * interval '1 second' AS duration 
FROM 	activity_hist.archive_pg_stat_activity aa
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour')  AND 
	backend_type = 'client backend' AND datname != 'postgres' AND
	( aa.wait_event_type IS NOT NULL  ) 
GROUP BY aa.wait_event_type , aa.wait_event , aa.query ,aa.queryid		
UNION 
SELECT 
	ha.query ,ha.queryid,
	count(*) * interval '1 second' AS duration 
FROM 	activity_hist.history_pg_stat_activity_for_reports ha
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour')  AND 
	backend_type = 'client backend' AND datname != 'postgres' AND				
	( ha.wait_event_type IS NOT NULL  )
GROUP BY ha.wait_event_type , ha.wait_event , ha.query ,ha.queryid		
)
SELECT 	query , queryid , SUM( duration ) as duration 
FROM hist
GROUP BY  query , queryid 
ORDER BY 3 DESC 

์˜ˆ๋ฅผ ๋“ค๋ฉด :

-------------------------------------------------------------------
| TOTAL WAITINGS TIME FOR QUERIES : 21:55:04
+----+----------------------------------------+--------------------
|   #|                                 queryid|            duration
+----+----------------------------------------+--------------------
|   1|                      389015618226997618|            16:19:05
|   2|                                        |            03:47:04
|   3|                     8085340880788646241|            00:40:20
|   4|                     4710212362688288619|            00:13:35
|   5|                     9150846928388977274|            00:12:25
|   6|                       28942442626229688|            00:11:32
|   7|                     1237430309438971376|            00:09:45
|   8|                     2649515222348904837|            00:09:37
|   9|                                        |            00:03:45
|  10|                     3167065002719415275|            00:02:20
|  11|                     5731212217001535134|            00:02:13
|  12|                     8304755792398128062|            00:01:31
|  13|                     2649515222348904837|            00:00:59
|  14|                     2649515222348904837|            00:00:22
|  15|                                        |            00:00:12
|  16|                     3422818749220588372|            00:00:08
|  17|                    -5730801771815999400|            00:00:03
|  18|                    -1473395109729441239|            00:00:02
|  19|                     2404820632950544954|            00:00:02
|  20|                    -6572922443698419129|            00:00:02
|  21|                     2369289265278398647|            00:00:01
|  22|                      180077086776069052|            00:00:01
+----+----------------------------------------+--------------------

์ฟผ๋ฆฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค

์š”์ฒญ:

WITH hist AS
(
SELECT 
	aa.wait_event_type , aa.wait_event 
FROM 	activity_hist.archive_pg_stat_activity aa
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND 
	backend_type = 'client backend' AND datname != 'postgres' AND
	aa.wait_event IS NOT NULL 
GROUP BY aa.wait_event_type , aa.wait_event
UNION 
SELECT 
	ha.wait_event_type , ha.wait_event 
FROM 	activity_hist.history_pg_stat_activity_for_reports ha
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND 
	backend_type = 'client backend' AND datname != 'postgres' AND
	ha.wait_event IS NOT NULL 
GROUP BY ha.wait_event_type , ha.wait_event		
)
SELECT 	wait_event_type , wait_event 
FROM hist
GROUP BY wait_event_type , wait_event
ORDER BY 1 ASC,2 ASC

----------------------------------------------------------------------

WITH hist AS
(
SELECT 
	aa.wait_event_type , aa.wait_event , aa.query ,aa.queryid ,			
	count(*) * interval '1 second' AS duration 
FROM 	activity_hist.archive_pg_stat_activity aa
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND 
	backend_type = 'client backend' AND datname != 'postgres' AND
	( aa.wait_event_type = waitings_stat_rec.wait_event_type AND aa.wait_event = waitings_stat_rec.wait_event )
GROUP BY aa.wait_event_type , aa.wait_event , aa.query ,aa.queryid		
UNION 
SELECT 
	ha.wait_event_type , ha.wait_event , ha.query ,ha.queryid,
	count(*) * interval '1 second' AS duration 
FROM 	activity_hist.history_pg_stat_activity_for_reports ha
WHERE timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND 
	backend_type = 'client backend' AND datname != 'postgres' AND				
	( ha.wait_event_type = waitings_stat_rec.wait_event_type AND ha.wait_event = waitings_stat_rec.wait_event )
GROUP BY ha.wait_event_type , ha.wait_event , ha.query ,ha.queryid		
)
SELECT 	query , queryid , SUM( duration ) as duration 
FROM hist
GROUP BY  query , queryid 
ORDER BY 3 DESC

์˜ˆ :

------------------------------------------------
| WAITINGS FOR QUERIES
+-----------------------------------------------
|                      wait_event_type = Client|
|                       wait_event = ClientRead|
|                        Total time  = 00:46:56|
------------------------------------------------
|    #|             queryid|            duration
+-----+--------------------+--------------------
|    1| 8085340880788646241|            00:40:20
|    2|                    |            00:03:45
|    3| 5731212217001535134|            00:01:53
|    4|                    |            00:00:12
|    5| 9150846928388977274|            00:00:09
|    6| 3422818749220588372|            00:00:08
|    7| 1237430309438971376|            00:00:06
|    8|   28942442626229688|            00:00:05
|    9| 4710212362688288619|            00:00:05
|   10|-5730801771815999400|            00:00:03
|   11| 8304755792398128062|            00:00:02
|   12|-6572922443698419129|            00:00:02
|   13|-1473395109729441239|            00:00:02
|   14| 2404820632950544954|            00:00:02
|   15|  180077086776069052|            00:00:01
|   16| 2369289265278398647|            00:00:01

+-----------------------------------------------
|                          wait_event_type = IO|
|                      wait_event = BufFileRead|
|                        Total time  = 00:00:38|
------------------------------------------------
|    #|             queryid|            duration
+-----+--------------------+--------------------
|    1|   28942442626229688|            00:00:38

+-----------------------------------------------

์ž ๊ธด ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ก

๋ฌธ์˜:

SELECT 
MIN(date_trunc('second',timepoint)) AS started , 
	count(*) * interval '1 second' as duration ,
	pid , blocking_pids , relation , mode , locktype 	 
FROM 
	activity_hist.archive_locking al 
WHERE 
	timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
	NOT granted AND 
	locktype = 'relation' 
GROUP BY pid , blocking_pids , relation , mode , locktype			
UNION
SELECT 
	MIN(date_trunc('second',timepoint)) AS started , 
	count(*) * interval '1 second' as duration ,
	pid , blocking_pids , relation , mode , locktype
FROM 
	activity_hist.history_locking 
WHERE 
	timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
	NOT granted AND 
	locktype = 'relation' 
GROUP BY pid , blocking_pids , relation , mode , locktype			
ORDER BY 1

์˜ˆ :

------------------------------------- ------------------------------------- --------------------------------- | ์ž ๊ธด ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ก +------+----------+------+--------- --+------------ ---------+---------+------ --------------- +------ | #| PID| ์‹œ์ž‘๋จ| ๊ธฐ๊ฐ„| Blocking_pids| ๊ด€๊ณ„| ๋ชจ๋“œ| ์ž ๊ธˆ ์œ ํ˜• +----------+----------+-------+---------- +--------- ---------+------------+------- ------------+---- -------------- | 1| 26224| 2019-09-02 19:32:16| 00:01:45| {26211}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 2| 26390| 2019-09-02 19:34:03| 00:00:53| {26211}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 3| 26391| 2019-09-02 19:34:03| 00:00:53| {26211}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 4| 26531| 2019-09-02 19:35:27| 00:00:12| {26211}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 5| 27284| 2019-09-02 19:44:02| 00:00:19| {27276}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 6| 27283| 2019-09-02 19:44:02| 00:00:19| {27276}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 7| 27286| 2019-09-02 19:44:02| 00:00:19| {27276}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 8| 27423| 2019-09-02 19:45:24| 00:00:12| {27394}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 9| 27648| 2019-09-02 19:48:06| 00:00:20| {27647}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 10| 27650| 2019-09-02 19:48:06| 00:00:20| {27647}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 11| 27735| 2019-09-02 19:49:08| 00:00:06| {27650}| 16541| ์ ‘๊ทผ๋…์ ์ž ๊ธˆ| ๊ด€๊ณ„ | 12| 28380| 2019-09-02 19:56:03| 00:01:56| {28379}| 16541| ์•ก์„ธ์Šค๊ณต์œ ์ž ๊ธˆ| ๊ด€๊ณ„ | 13| 28379| 2019-09-02 19:56:03| 00:00:01| 28377| 16541| ์ ‘๊ทผ๋…์ ์ž ๊ธˆ| ๊ด€๊ณ„ | | | | | 28376| | 

์ฐจ๋‹จ ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ก

์š”์ฒญ:

SELECT 
blocking_pids 
FROM 
	activity_hist.archive_locking al 
WHERE 
	timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
	NOT granted AND 
	locktype = 'relation' 
GROUP BY blocking_pids 		
UNION
SELECT 
	blocking_pids 
FROM 
	activity_hist.history_locking 
WHERE 
	timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
	NOT granted AND 
	locktype = 'relation' 
GROUP BY blocking_pids 		
ORDER BY 1

---------------------------------------------------------------

SELECT 
	pid , usename , application_name , datname ,
	MIN(date_trunc('second',timepoint)) as started , 
	count(*) * interval '1 second' as duration ,		 
	state , 
	query
				FROM  	activity_hist.archive_pg_stat_activity
				WHERE 	pid= current_pid AND 
						timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') 						 
				GROUP BY pid , usename , application_name , 
						datname , 
						state_change, 
						state , 
						query 
				UNION
				SELECT 
					pid , usename , application_name , datname ,
					MIN(date_trunc('second',timepoint)) as started , 
					count(*) * interval '1 second' as duration ,		 
					state , 
					query
				FROM  	activity_hist.history_pg_stat_activity_for_reports
				WHERE 	pid= current_pid AND 
						timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') 						 
				GROUP BY pid , usename , application_name , 
						datname , 
						state_change, 
						state , 
						query 
				ORDER BY 5 , 1

์˜ˆ :

------------------------------------- ------------------------------------- ------------------------------------- ---------- ์ฐจ๋‹จ ํ”„๋กœ์„ธ์Šค ๊ธฐ๋ก +------+------------+------- ---+---------+------------+------------- ----+---------+-------- - -----+--------------- | #| PID| ์‚ฌ์šฉ์ž ์ด๋ฆ„| ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜_์ด๋ฆ„| ๋ฐ์ดํ„ฐ ์ด๋ฆ„| ์‹œ์ž‘๋จ| ๊ธฐ๊ฐ„| ์ƒํƒœ| ์ฟผ๋ฆฌ +----------+----------+----------+------+ --------- -+---------+------ ---+------ -------------+--- ------- ----------------- | 1| 26211| tuser| psql| tdb1| 2019-09-02 19:31:54| 00:00:04| ์œ ํœด| | 2| 26211| tuser| psql| tdb1| 2019-09-02 19:31:58| 00:00:06| ๊ฑฐ๋ž˜ ์œ ํœด ์ƒํƒœ| ์‹œ์ž‘ํ•˜๋‹ค; | 3| 26211| tuser| psql| tdb1| 2019-09-02 19:32:16| 00:01:45| ๊ฑฐ๋ž˜ ์œ ํœด ์ƒํƒœ| ์ž ๊ธˆ ํ…Œ์ด๋ธ” Wafer_data; | 4| 26211| tuser| psql| tdb1| 2019-09-02 19:35:54| 00:01:23| ์œ ํœด| ์ €์ง€๋ฅด๋‹ค; | 5| 26211| tuser| psql| tdb1| 2019-09-02 19:38:46| 00:00:02| ๊ฑฐ๋ž˜ ์œ ํœด ์ƒํƒœ| ์‹œ์ž‘ํ•˜๋‹ค; | 6| 26211| tuser| psql| tdb1| 2019-09-02 19:38:54| 00:00:08| ๊ฑฐ๋ž˜ ์œ ํœด ์ƒํƒœ| ์ž ๊ธˆ ํ…Œ์ด๋ธ” Wafer_data; | 7| 26211| tuser| psql| tdb1| 2019-09-02 19:39:08| 00:42:42| ์œ ํœด| ์ €์ง€๋ฅด๋‹ค; | 8| 26211| tuser| psql| tdb1| 2019-09-03 07:12:07| 00:00:52| ํ™œ์„ฑ| test_del()์„ ์„ ํƒํ•˜์„ธ์š”.

๊ฐœ๋ฐœ.

ํ‘œ์‹œ๋œ ๊ธฐ๋ณธ ์ฟผ๋ฆฌ์™€ ๊ฒฐ๊ณผ ๋ณด๊ณ ์„œ๋Š” ์ด๋ฏธ ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ๋ถ„์„ํ•  ๋•Œ ์ž‘์—…์„ ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.
๊ธฐ๋ณธ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ค๋ผํด์˜ AWR๊ณผ ์–ด๋ ดํ’‹์ด ์œ ์‚ฌํ•œ ๋ณด๊ณ ์„œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์š”์•ฝ ๋ณด๊ณ ์„œ ์˜ˆ

+------------------------------------------------- ---------------------- | ํ™œ๋™ ๋ฐ ๋Œ€๊ธฐ์— ๋Œ€ํ•œ ํ†ตํ•ฉ ๋ณด๊ณ ์„œ. 

๊ณ„์†๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์ค„์€ ํ…Œ์ด๋ธ” ์ฑ„์šฐ๊ธฐ ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ์„ค๋ช…์ธ ์ž ๊ธˆ ๊ธฐ๋ก(pg_stat_locks) ์ƒ์„ฑ์ž…๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€