ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

ืื• ืงืฆืช ื˜ื˜ืจื™ืกื•ืœื•ื’ื™ื” ื™ื™ืฉื•ืžื™ืช.
ื›ืœ ื“ื‘ืจ ื—ื“ืฉ ื ืฉื›ื— ื”ื™ื˜ื‘ ื™ืฉืŸ.
ืืคื™ื’ืจืฃ.
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

ื”ืฆื”ืจืช ื”ื‘ืขื™ื”

ื™ืฉ ืฆื•ืจืš ืœื”ื•ืจื™ื“ ืžืขืช ืœืขืช ืืช ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื”ื ื•ื›ื—ื™ ืฉืœ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS ืœืžืืจื— ื”ืœื™ื ื•ืงืก ื”ืžืงื•ืžื™. ืœื ื‘ื–ืžืŸ ืืžืช, ืื‘ืœ, ื ื’ื™ื“, ื‘ืื™ื—ื•ืจ ืงืœ.
ืžืฉืš ื”ื”ื•ืจื“ื” ืฉืœ ืขื“ื›ื•ืŸ ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื”ื•ื 5 ื“ืงื•ืช.
ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ, ื‘-AWS, ืžืกื•ื‘ื‘ ื›ืœ ืฉืขื”.

ื›ืœื™ื ืžืฉื•ืžืฉื™ื

ื›ื“ื™ ืœื”ืขืœื•ืช ืืช ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ืœืžืืจื—, ื ืขืฉื” ืฉื™ืžื•ืฉ ื‘ืกืงืจื™ืคื˜ bash ืฉืงื•ืจื ืœ-AWS API "aws rds ื”ื•ืจื“ื”-db-log-file-portion".

ืคืจืžื˜ืจื™ื:

  • --db-instance-identifier: ืฉื ื”ืžื•ืคืข ื‘-AWS;
  • --log-file-name: ืฉื ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ืฉื ื•ืฆืจ ื›ืขืช
  • --max-item: ื”ืžืกืคืจ ื”ื›ื•ืœืœ ืฉืœ ืคืจื™ื˜ื™ื ืฉื”ื•ื—ื–ืจื• ื‘ืคืœื˜ ืฉืœ ื”ืคืงื•ื“ื”.ื’ื•ื“ืœ ื”ื ืชื— ืฉืœ ื”ืงื•ื‘ืฅ ืฉื”ื•ืจื“.
  • --starting-token: Starting token token

ื‘ืžืงืจื” ื”ืกืคืฆื™ืคื™ ื”ื–ื”, ื”ืžืฉื™ืžื” ืฉืœ ื”ื•ืจื“ืช ื™ื•ืžื ื™ื ื”ืชืขื•ืจืจื” ื‘ืžื”ืœืš ื”ืขื‘ื•ื“ื” ืขืœ ื ื™ื˜ื•ืจ ื‘ื™ืฆื•ืขื™ื ืฉืœ ืฉืื™ืœืชื•ืช PostgreSQL.

ื›ืŸ, ื•ืคืฉื•ื˜ - ืžืฉื™ืžื” ืžืขื ื™ื™ื ืช ืœื”ื“ืจื›ื” ื•ื’ื™ื•ื•ืŸ ื‘ืฉืขื•ืช ื”ืขื‘ื•ื“ื”.
ืื ื™ ืžื ื™ื— ืฉื”ื‘ืขื™ื” ื›ื‘ืจ ื ืคืชืจื” ืžื›ื•ื— ื”ืฉื’ืจื”. ืื‘ืœ ื’ื•ื’ืœ ืžื”ื™ืจ ืœื ื”ืฆื™ืข ืคืชืจื•ื ื•ืช, ื•ืœื ื”ื™ื” ืจืฆื•ืŸ ืžื™ื•ื—ื“ ืœื—ืคืฉ ื™ื•ืชืจ ืœืขื•ืžืง. ื‘ื›ืœ ืžืงืจื”, ื–ื” ืื™ืžื•ืŸ ื˜ื•ื‘.

ืคื•ืจืžืœื™ื–ืฆื™ื” ืฉืœ ื”ืžืฉื™ืžื”

ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื”ืกื•ืคื™ ื”ื•ื ืงื‘ื•ืฆื” ืฉืœ ืฉื•ืจื•ืช ื‘ืื•ืจืš ืžืฉืชื ื”. ืžื‘ื—ื™ื ื” ื’ืจืคื™ืช, ื ื™ืชืŸ ืœื™ื™ืฆื’ ืืช ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื›ืš:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

ื–ื” ื›ื‘ืจ ืžื–ื›ื™ืจ ืœืš ืžืฉื”ื•? ืžื” ื”ืงืฉืจ ืœ"ื˜ื˜ืจื™ืก"? ื•ื”ื ื” ืžื”.
ืื ื ืฆื™ื’ ืืช ื”ืืคืฉืจื•ื™ื•ืช ื”ืืคืฉืจื™ื•ืช ืฉืขื•ืœื•ืช ื‘ืขืช ื˜ืขื™ื ืช ื”ืงื•ื‘ืฅ ื”ื‘ื ื‘ืฆื•ืจื” ื’ืจืคื™ืช (ืœืžืขืŸ ื”ืคืฉื˜ื•ืช, ื‘ืžืงืจื” ื–ื”, ืชื ื• ืœืฉื•ืจื•ืช ืœื”ื™ื•ืช ื‘ืื•ืชื• ืื•ืจืš), ื ืงื‘ืœ ื“ืžื•ื™ื•ืช ื˜ื˜ืจื™ืก ืกื˜ื ื“ืจื˜ื™ื•ืช:

1) ื”ืงื•ื‘ืฅ ื™ืจื“ ื‘ืžืœื•ืื• ื•ื”ื•ื ืกื•ืคื™. ื’ื•ื“ืœ ื”ื ืชื— ื’ื“ื•ืœ ื™ื•ืชืจ ืžื’ื•ื“ืœ ื”ืงื•ื‘ืฅ ื”ืกื•ืคื™:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

2) ืœืงื•ื‘ืฅ ื™ืฉ ื”ืžืฉืš. ื’ื•ื“ืœ ื”ื ืชื— ืงื˜ืŸ ืžื’ื•ื“ืœ ื”ืงื•ื‘ืฅ ื”ืกื•ืคื™:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

3) ื”ืงื•ื‘ืฅ ื”ื•ื ื”ืžืฉืš ืœืงื•ื‘ืฅ ื”ืงื•ื“ื ื•ื™ืฉ ืœื• ื”ืžืฉืš. ื’ื•ื“ืœ ื”ื ืชื— ืงื˜ืŸ ืžื”ื’ื•ื“ืœ ืฉืœ ืฉืืจ ื”ืงื•ื‘ืฅ ื”ืกื•ืคื™:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

4) ื”ืงื•ื‘ืฅ ื”ื•ื ื”ืžืฉืš ืœืงื•ื‘ืฅ ื”ืงื•ื“ื ื•ื”ื•ื ืกื•ืคื™. ื’ื•ื“ืœ ื”ื ืชื— ื’ื“ื•ืœ ื™ื•ืชืจ ืžื”ื’ื•ื“ืœ ืฉืœ ืฉืืจ ื”ืงื•ื‘ืฅ ื”ืกื•ืคื™:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

ื”ืžืฉื™ืžื” ื”ื™ื ืœื”ืจื›ื™ื‘ ืžืœื‘ืŸ ืื• ืœืฉื—ืง ื˜ื˜ืจื™ืก ื‘ืจืžื” ื—ื“ืฉื”.
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

ื‘ืขื™ื•ืช ื”ืžืชืขื•ืจืจื•ืช ื‘ืžื”ืœืš ืคืชืจื•ืŸ ื”ื‘ืขื™ื”

1) ื”ื“ื‘ื™ืงื• ื—ื•ื˜ ืฉืœ 2 ื—ืœืงื™ื

ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS
ื‘ืื•ืคืŸ ื›ืœืœื™, ืœื ื”ื™ื• ื‘ืขื™ื•ืช ืžื™ื•ื—ื“ื•ืช. ืžืฉื™ืžื” ืกื˜ื ื“ืจื˜ื™ืช ืžืงื•ืจืก ื”ืชื›ื ื•ืช ื”ืจืืฉื•ื ื™.

ื’ื•ื“ืœ ื”ื’ืฉื” ืื•ืคื˜ื™ืžืœื™

ืื‘ืœ ื–ื” ืงืฆืช ื™ื•ืชืจ ืžืขื ื™ื™ืŸ.
ืœืžืจื‘ื” ื”ืฆืขืจ, ืื™ืŸ ื“ืจืš ืœื”ืฉืชืžืฉ ื‘ื”ื™ืกื˜ ืœืื—ืจ ืชื•ื•ื™ืช ื”-start chunk:

ื›ืคื™ ืฉืืชื” ื›ื‘ืจ ื™ื•ื“ืข ื”ืืคืฉืจื•ืช --starting-token ืžืฉืžืฉืช ื›ื“ื™ ืœืฆื™ื™ืŸ ื”ื™ื›ืŸ ืœื”ืชื—ื™ืœ ืืช ื”ืขื™ืžื•ื“. ืืคืฉืจื•ืช ื–ื• ืœื•ืงื—ืช ืขืจื›ื™ ืžื—ืจื•ื–ืช, ืžื” ืฉืื•ืžืจ ืฉืื ืชื ืกื” ืœื”ื•ืกื™ืฃ ืขืจืš ื”ื™ืกื˜ ืžื•ืœ ืžื—ืจื•ื–ืช ื”ืืกื™ืžื•ืŸ ื”ื‘ื, ื”ืืคืฉืจื•ืช ืœื ืชื™ืœืงื— ื‘ื—ืฉื‘ื•ืŸ ื›ืงื™ื–ื•ื–.

ื•ืœื›ืŸ, ืืชื” ืฆืจื™ืš ืœืงืจื•ื ื‘ื ืชื—ื™ื-ืžื ื•ืช.
ืื ืืชื” ืงื•ืจื ื‘ืžื ื•ืช ื’ื“ื•ืœื•ืช, ืื– ืžืกืคืจ ื”ืงืจื™ืื•ืช ื™ื”ื™ื” ืžื™ื ื™ืžืœื™, ืื‘ืœ ื”ื ืคื— ื™ื”ื™ื” ืžืงืกื™ืžืœื™.
ืื ืืชื” ืงื•ืจื ื‘ืžื ื•ืช ืงื˜ื ื•ืช, ืื– ืœื”ื™ืคืš, ืžืกืคืจ ื”ืงืจื™ืื•ืช ื™ื”ื™ื” ืžืงืกื™ืžืœื™, ืื‘ืœ ื”ื ืคื— ื™ื”ื™ื” ืžื™ื ื™ืžืœื™.
ืœื›ืŸ, ืขืœ ืžื ืช ืœืฆืžืฆื ืืช ื”ืชื ื•ืขื” ื•ืœืžืขืŸ ื”ื™ื•ืคื™ ื”ื›ื•ืœืœ ืฉืœ ื”ืคืชืจื•ืŸ, ื”ื™ื™ืชื™ ืฆืจื™ืš ืœืžืฆื•ื ืคืชืจื•ืŸ ื›ืœืฉื”ื•, โ€‹โ€‹ืฉืœืฆืขืจื™ ื ืจืื” ืงืฆืช ื›ืžื• ืงื‘.

ืœืฉื ื”ืžื—ืฉื”, ื‘ื•ืื• ื ืฉืงื•ืœ ืืช ืชื”ืœื™ืš ื”ื•ืจื“ืช ืงื•ื‘ืฅ ื™ื•ืžืŸ ื‘-2 ื’ืจืกืื•ืช ืคืฉื•ื˜ื•ืช ืžืื•ื“. ืžืกืคืจ ื”ืงืจื™ืื•ืช ื‘ืฉื ื™ ื”ืžืงืจื™ื ืชืœื•ื™ ื‘ื’ื•ื“ืœ ื”ืžื ื”.

1) ื˜ืขืŸ ื‘ืžื ื•ืช ืงื˜ื ื•ืช:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

2) ื˜ืขืŸ ื‘ืžื ื•ืช ื’ื“ื•ืœื•ืช:
ื”ืขืœืืช ื™ื•ืžืŸ PostgreSQL ืžื”ืขื ืŸ ืฉืœ AWS

ื›ืจื’ื™ืœ, ื”ืคืชืจื•ืŸ ื”ืื•ืคื˜ื™ืžืœื™ ื”ื•ื ื‘ืืžืฆืข.
ื’ื•ื“ืœ ื”ืžื ื” ืžื™ื ื™ืžืœื™, ืืš ื‘ืชื”ืœื™ืš ื”ืงืจื™ืื” ื ื™ืชืŸ ืœื”ื’ื“ื™ืœ ืืช ื”ื’ื•ื“ืœ ื›ื“ื™ ืœื”ืคื—ื™ืช ืืช ืžืกืคืจ ื”ืงืจื™ืื•ืช.

ื–ื” ืจืื•ื™ ืœืฆื™ื•ืŸ ืฉื”ื‘ืขื™ื” ืฉืœ ื‘ื—ื™ืจืช ื”ื’ื•ื“ืœ ื”ืื•ืคื˜ื™ืžืœื™ ืฉืœ ื—ืœืง ื”ืงืจื™ืื” ืขื“ื™ื™ืŸ ืœื ื ืคืชืจื” ืœื—ืœื•ื˜ื™ืŸ ื•ื“ื•ืจืฉืช ืžื—ืงืจ ื•ื ื™ืชื•ื— ืžืขืžื™ืงื™ื ื™ื•ืชืจ. ืื•ืœื™ ืงืฆืช ืื—ืจ ื›ืš.

ืชื™ืื•ืจ ื›ืœืœื™ ืฉืœ ื”ื™ื™ืฉื•ื

ื˜ื‘ืœืื•ืช ืฉื™ืจื•ืช ืžืฉื•ืžืฉื•ืช

CREATE TABLE endpoint
(
id SERIAL ,
host text 
);

TABLE database
(
id SERIAL , 
โ€ฆ
last_aws_log_time text ,
last_aws_nexttoken text ,
aws_max_item_size integer 
);
last_aws_log_time โ€” ะฒั€ะตะผะตะฝะฝะฐั ะผะตั‚ะบะฐ ะฟะพัะปะตะดะฝะตะณะพ ะทะฐะณั€ัƒะถะตะฝะฝะพะณะพ ะปะพะณ-ั„ะฐะนะปะฐ ะฒ ั„ะพั€ะผะฐั‚ะต YYYY-MM-DD-HH24.
last_aws_nexttoken โ€” ั‚ะตะบัั‚ะพะฒะฐั ะผะตั‚ะบะฐ ะฟะพัะปะตะดะฝะตะน ะทะฐะณั€ัƒะถะตะฝะฝะพะน ะฟะพั€ั†ะธะธ.
aws_max_item_size- ัะผะฟะธั€ะธั‡ะตัะบะธะผ ะฟัƒั‚ะตะผ, ะฟะพะดะพะฑั€ะฐะฝะฝั‹ะน ะฝะฐั‡ะฐะปัŒะฝั‹ะน ั€ะฐะทะผะตั€ ะฟะพั€ั†ะธะธ.

ื”ื˜ืงืกื˜ ื”ืžืœื ืฉืœ ื”ืชืกืจื™ื˜

download_aws_piece.sh

#!/bin/bash
#########################################################
# download_aws_piece.sh
# downloan piece of log from AWS
# version HABR
 let min_item_size=1024
 let max_item_size=1048576
 let growth_factor=3
 let growth_counter=1
 let growth_counter_max=3

 echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:''STARTED'
 
 AWS_LOG_TIME=$1
 echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:AWS_LOG_TIME='$AWS_LOG_TIME
  
 database_id=$2
 echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:database_id='$database_id
 RESULT_FILE=$3 
  
 endpoint=`psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE_DATABASE -A -t -c "select e.host from endpoint e join database d on e.id = d.endpoint_id where d.id = $database_id "`
 echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:endpoint='$endpoint
  
 db_instance=`echo $endpoint | awk -F"." '{print toupper($1)}'`
 
 echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:db_instance='$db_instance

 LOG_FILE=$RESULT_FILE'.tmp_log'
 TMP_FILE=$LOG_FILE'.tmp'
 TMP_MIDDLE=$LOG_FILE'.tmp_mid'  
 TMP_MIDDLE2=$LOG_FILE'.tmp_mid2'  
  
 current_aws_log_time=`psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -A -t -c "select last_aws_log_time from database where id = $database_id "`

 echo $(date +%Y%m%d%H%M)':      download_aws_piece.sh:current_aws_log_time='$current_aws_log_time
  
  if [[ $current_aws_log_time != $AWS_LOG_TIME  ]];
  then
    is_new_log='1'
	if ! psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -v ON_ERROR_STOP=1 -A -t -q -c "update database set last_aws_log_time = '$AWS_LOG_TIME' where id = $database_id "
	then
	  echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: FATAL_ERROR - update database set last_aws_log_time .'
	  exit 1
	fi
  else
    is_new_log='0'
  fi
  
  echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:is_new_log='$is_new_log
  
  let last_aws_max_item_size=`psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -A -t -c "select aws_max_item_size from database where id = $database_id "`
  echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: last_aws_max_item_size='$last_aws_max_item_size
  
  let count=1
  if [[ $is_new_log == '1' ]];
  then    
	echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: START DOWNLOADING OF NEW AWS LOG'
	if ! aws rds download-db-log-file-portion 
		--max-items $last_aws_max_item_size 
		--region REGION 
		--db-instance-identifier  $db_instance 
		--log-file-name error/postgresql.log.$AWS_LOG_TIME > $LOG_FILE
	then
		echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: FATAL_ERROR - Could not get log from AWS .'
		exit 2
	fi  	
  else
    next_token=`psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -v ON_ERROR_STOP=1 -A -t -c "select last_aws_nexttoken from database where id = $database_id "`
	
	if [[ $next_token == '' ]];
	then
	  next_token='0'	  
	fi
	
	echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: CONTINUE DOWNLOADING OF AWS LOG'
	if ! aws rds download-db-log-file-portion 
	    --max-items $last_aws_max_item_size 
		--starting-token $next_token 
		--region REGION 
		--db-instance-identifier  $db_instance 
		--log-file-name error/postgresql.log.$AWS_LOG_TIME > $LOG_FILE
	then
		echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: FATAL_ERROR - Could not get log from AWS .'
		exit 3
	fi       
	
	line_count=`cat  $LOG_FILE | wc -l`
	let lines=$line_count-1
	  
	tail -$lines $LOG_FILE > $TMP_MIDDLE 
	mv -f $TMP_MIDDLE $LOG_FILE
  fi
  
  next_token_str=`cat $LOG_FILE | grep NEXTTOKEN` 
  next_token=`echo $next_token_str | awk -F" " '{ print $2}' `
  
  grep -v NEXTTOKEN $LOG_FILE  > $TMP_FILE 
  
  if [[ $next_token == '' ]];
  then
	  cp $TMP_FILE $RESULT_FILE
	  
	  echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:  NEXTTOKEN NOT FOUND - FINISH '
	  rm $LOG_FILE 
	  rm $TMP_FILE
	  rm $TMP_MIDDLE
          rm $TMP_MIDDLE2	  
	  exit 0  
  else
	psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -v ON_ERROR_STOP=1 -A -t -q -c "update database set last_aws_nexttoken = '$next_token' where id = $database_id "
  fi
  
  first_str=`tail -1 $TMP_FILE`
  
  line_count=`cat  $TMP_FILE | wc -l`
  let lines=$line_count-1    
  
  head -$lines $TMP_FILE  > $RESULT_FILE

###############################################
# MAIN CIRCLE
  let count=2
  while [[ $next_token != '' ]];
  do 
    echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: count='$count
	
	echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: START DOWNLOADING OF AWS LOG'
	if ! aws rds download-db-log-file-portion 
             --max-items $last_aws_max_item_size 
             --starting-token $next_token 
             --region REGION 
             --db-instance-identifier  $db_instance 
             --log-file-name error/postgresql.log.$AWS_LOG_TIME > $LOG_FILE
	then
		echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: FATAL_ERROR - Could not get log from AWS .'
		exit 4
	fi

	next_token_str=`cat $LOG_FILE | grep NEXTTOKEN` 
	next_token=`echo $next_token_str | awk -F" " '{ print $2}' `

	TMP_FILE=$LOG_FILE'.tmp'
	grep -v NEXTTOKEN $LOG_FILE  > $TMP_FILE  
	
	last_str=`head -1 $TMP_FILE`
  
    if [[ $next_token == '' ]];
	then
	  concat_str=$first_str$last_str
	  	  
	  echo $concat_str >> $RESULT_FILE
		 
	  line_count=`cat  $TMP_FILE | wc -l`
	  let lines=$line_count-1
	  
	  tail -$lines $TMP_FILE >> $RESULT_FILE
	  
	  echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:  NEXTTOKEN NOT FOUND - FINISH '
	  rm $LOG_FILE 
	  rm $TMP_FILE
	  rm $TMP_MIDDLE
          rm $TMP_MIDDLE2	  
	  exit 0  
	fi
	
    if [[ $next_token != '' ]];
	then
		let growth_counter=$growth_counter+1
		if [[ $growth_counter -gt $growth_counter_max ]];
		then
			let last_aws_max_item_size=$last_aws_max_item_size*$growth_factor
			let growth_counter=1
		fi
	
		if [[ $last_aws_max_item_size -gt $max_item_size ]]; 
		then
			let last_aws_max_item_size=$max_item_size
		fi 

	  psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -A -t -q -c "update database set last_aws_nexttoken = '$next_token' where id = $database_id "
	  
	  concat_str=$first_str$last_str
	  	  
	  echo $concat_str >> $RESULT_FILE
		 
	  line_count=`cat  $TMP_FILE | wc -l`
	  let lines=$line_count-1
	  
	  #############################
	  #Get middle of file
	  head -$lines $TMP_FILE > $TMP_MIDDLE
	  
	  line_count=`cat  $TMP_MIDDLE | wc -l`
	  let lines=$line_count-1
	  tail -$lines $TMP_MIDDLE > $TMP_MIDDLE2
	  
	  cat $TMP_MIDDLE2 >> $RESULT_FILE	  
	  
	  first_str=`tail -1 $TMP_FILE`	  
	fi
	  
    let count=$count+1

  done
#
#################################################################

exit 0  

ืงื˜ืขื™ ืชืกืจื™ื˜ ืขื ื›ืžื” ื”ืกื‘ืจื™ื:

ืคืจืžื˜ืจื™ ืงืœื˜ ืฉืœ ืกืงืจื™ืคื˜:

  • ื—ื•ืชืžืช ื–ืžืŸ ืฉืœ ืฉื ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื‘ืคื•ืจืžื˜ YYYY-MM-DD-HH24: AWS_LOG_TIME=$1
  • ืžื–ื”ื” ืžืกื“ ื ืชื•ื ื™ื: database_id=$2
  • ืฉื ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ืฉื ืืกืฃ: RESULT_FILE=$3

ืงื‘ืœ ืืช ื—ื•ืชืžืช ื”ื–ืžืŸ ืฉืœ ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื”ืื—ืจื•ืŸ ืฉื”ื•ืขืœื”:

current_aws_log_time=`psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -A -t -c "select last_aws_log_time from database where id = $database_id "`

ืื ื—ื•ืชืžืช ื”ื–ืžืŸ ืฉืœ ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื”ืื—ืจื•ืŸ ืฉื ื˜ืขืŸ ืœื ืชื•ืืžืช ืœืคืจืžื˜ืจ ื”ืงืœื˜, ืงื•ื‘ืฅ ื™ื•ืžืŸ ื—ื“ืฉ ื ื˜ืขืŸ:

if [[ $current_aws_log_time != $AWS_LOG_TIME  ]];
  then
    is_new_log='1'
	if ! psql -h ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -v ON_ERROR_STOP=1 -A -t -c "update database set last_aws_log_time = '$AWS_LOG_TIME' where id = $database_id "
	then
	  echo '***download_aws_piece.sh -FATAL_ERROR - update database set last_aws_log_time .'
	  exit 1
	fi
  else
    is_new_log='0'
  fi

ืื ื• ืžืงื‘ืœื™ื ืืช ื”ืขืจืš ืฉืœ ืชื•ื•ื™ืช nexttoken ืžื”ืงื•ื‘ืฅ ืฉื ื˜ืขืŸ:

  next_token_str=`cat $LOG_FILE | grep NEXTTOKEN` 
  next_token=`echo $next_token_str | awk -F" " '{ print $2}' `

ื”ืกื™ืžืŸ ืœืกื™ื•ื ื”ื”ื•ืจื“ื” ื”ื•ื ื”ืขืจืš ื”ืจื™ืง ืฉืœ nexttoken.

ื‘ืœื•ืœืื”, ืื ื• ืกื•ืคืจื™ื ื—ืœืงื™ื ืžื”ืงื•ื‘ืฅ, ืœืื•ืจืš ื”ื“ืจืš, ืžืฉืจืฉืจื™ื ืฉื•ืจื•ืช ื•ืžื’ื“ื™ืœื™ื ืืช ื’ื•ื“ืœ ื”ื—ืœืง:
ืœื•ืœืื” ืจืืฉื™ืช

# MAIN CIRCLE
  let count=2
  while [[ $next_token != '' ]];
  do 
    echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: count='$count
	
	echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: START DOWNLOADING OF AWS LOG'
	if ! aws rds download-db-log-file-portion 
     --max-items $last_aws_max_item_size 
	 --starting-token $next_token 
     --region REGION 
     --db-instance-identifier  $db_instance 
     --log-file-name error/postgresql.log.$AWS_LOG_TIME > $LOG_FILE
	then
		echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh: FATAL_ERROR - Could not get log from AWS .'
		exit 4
	fi

	next_token_str=`cat $LOG_FILE | grep NEXTTOKEN` 
	next_token=`echo $next_token_str | awk -F" " '{ print $2}' `

	TMP_FILE=$LOG_FILE'.tmp'
	grep -v NEXTTOKEN $LOG_FILE  > $TMP_FILE  
	
	last_str=`head -1 $TMP_FILE`
  
    if [[ $next_token == '' ]];
	then
	  concat_str=$first_str$last_str
	  	  
	  echo $concat_str >> $RESULT_FILE
		 
	  line_count=`cat  $TMP_FILE | wc -l`
	  let lines=$line_count-1
	  
	  tail -$lines $TMP_FILE >> $RESULT_FILE
	  
	  echo $(date +%Y%m%d%H%M)':    download_aws_piece.sh:  NEXTTOKEN NOT FOUND - FINISH '
	  rm $LOG_FILE 
	  rm $TMP_FILE
	  rm $TMP_MIDDLE
         rm $TMP_MIDDLE2	  
	  exit 0  
	fi
	
    if [[ $next_token != '' ]];
	then
		let growth_counter=$growth_counter+1
		if [[ $growth_counter -gt $growth_counter_max ]];
		then
			let last_aws_max_item_size=$last_aws_max_item_size*$growth_factor
			let growth_counter=1
		fi
	
		if [[ $last_aws_max_item_size -gt $max_item_size ]]; 
		then
			let last_aws_max_item_size=$max_item_size
		fi 

	  psql -h MONITOR_ENDPOINT.rds.amazonaws.com -U USER -d MONITOR_DATABASE -A -t -q -c "update database set last_aws_nexttoken = '$next_token' where id = $database_id "
	  
	  concat_str=$first_str$last_str
	  	  
	  echo $concat_str >> $RESULT_FILE
		 
	  line_count=`cat  $TMP_FILE | wc -l`
	  let lines=$line_count-1
	  
	  #############################
	  #Get middle of file
	  head -$lines $TMP_FILE > $TMP_MIDDLE
	  
	  line_count=`cat  $TMP_MIDDLE | wc -l`
	  let lines=$line_count-1
	  tail -$lines $TMP_MIDDLE > $TMP_MIDDLE2
	  
	  cat $TMP_MIDDLE2 >> $RESULT_FILE	  
	  
	  first_str=`tail -1 $TMP_FILE`	  
	fi
	  
    let count=$count+1

  done

ืžื” ื”ืœืื”?

ืื–, ืžืฉื™ืžืช ื”ื‘ื™ื ื™ื™ื ื”ืจืืฉื•ื ื” - "ื”ื•ืจื“ ืืช ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ืžื”ืขื ืŸ" ื ืคืชืจื”. ืžื” ืœืขืฉื•ืช ืขื ื”ื™ื•ืžืŸ ืฉื”ื•ืจื“?
ืจืืฉื™ืช ืขืœื™ืš ืœื ืชื— ืืช ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ื•ืœื—ืœืฅ ืžืžื ื• ืืช ื”ื‘ืงืฉื•ืช ื‘ืคื•ืขืœ.
ื”ืžืฉื™ืžื” ืœื ืžืื•ื“ ืงืฉื”. ื”-bash-script ื”ืคืฉื•ื˜ ื‘ื™ื•ืชืจ ืžืกืชื“ืจ ืžืฆื•ื™ืŸ.
upload_log_query.sh

#!/bin/bash
#########################################################
# upload_log_query.sh
# Upload table table from dowloaded aws file 
# version HABR
###########################################################  
echo 'TIMESTAMP:'$(date +%c)' Upload log_query table '
source_file=$1
echo 'source_file='$source_file
database_id=$2
echo 'database_id='$database_id

beginer=' '
first_line='1'
let "line_count=0"
sql_line=' '
sql_flag=' '    
space=' '
cat $source_file | while read line
do
  line="$space$line"

  if [[ $first_line == "1" ]]; then
    beginer=`echo $line | awk -F" " '{ print $1}' `
    first_line='0'
  fi

  current_beginer=`echo $line | awk -F" " '{ print $1}' `

  if [[ $current_beginer == $beginer ]]; then
    if [[ $sql_flag == '1' ]]; then
     sql_flag='0' 
     log_date=`echo $sql_line | awk -F" " '{ print $1}' `
     log_time=`echo $sql_line | awk -F" " '{ print $2}' `
     duration=`echo $sql_line | awk -F" " '{ print $5}' `

     #replace ' to ''
     sql_modline=`echo "$sql_line" | sed 's/'''/''''''/g'`
     sql_line=' '

	 ################
	 #PROCESSING OF THE SQL-SELECT IS HERE
     if ! psql -h ENDPOINT.rds.amazonaws.com -U USER -d DATABASE -v ON_ERROR_STOP=1 -A -t -c "select log_query('$ip_port',$database_id , '$log_date' , '$log_time' , '$duration' , '$sql_modline' )" 
     then
        echo 'FATAL_ERROR - log_query '
        exit 1
     fi
	 ################

    fi #if [[ $sql_flag == '1' ]]; then

    let "line_count=line_count+1"

    check=`echo $line | awk -F" " '{ print $8}' `
    check_sql=${check^^}    

    #echo 'check_sql='$check_sql
    
    if [[ $check_sql == 'SELECT' ]]; then
     sql_flag='1'    
     sql_line="$sql_line$line"
	 ip_port=`echo $sql_line | awk -F":" '{ print $4}' `
    fi
  else       

    if [[ $sql_flag == '1' ]]; then
      sql_line="$sql_line$line"
    fi   
    
  fi #if [[ $current_beginer == $beginer ]]; then

done

ื›ืขืช ืชื•ื›ืœ ืœืขื‘ื•ื“ ืขื ื”ืฉืื™ืœืชื” ืฉื—ื•ืœืฆื” ืžืงื•ื‘ืฅ ื”ื™ื•ืžืŸ.

ื•ื™ืฉ ื›ืžื” ืืคืฉืจื•ื™ื•ืช ืฉื™ืžื•ืฉื™ื•ืช.

ืฉืื™ืœืชื•ืช ืžื ื•ืชื—ื•ืช ื—ื™ื™ื‘ื•ืช ืœื”ื™ื•ืช ืžืื•ื—ืกื ื•ืช ื‘ืžืงื•ื ื›ืœืฉื”ื•. ืœืฉื ื›ืš, ื ืขืฉื” ืฉื™ืžื•ืฉ ื‘ื˜ื‘ืœืช ืฉื™ืจื•ืช. log_query

CREATE TABLE log_query
(
   id SERIAL ,
   queryid bigint ,
   query_md5hash text not null ,
   database_id integer not null ,  
   timepoint timestamp without time zone not null,
   duration double precision not null ,
   query text not null ,
   explained_plan text[],
   plan_md5hash text  , 
   explained_plan_wo_costs text[],
   plan_hash_value text  ,
   baseline_id integer ,
   ip text ,
   port text 
);
ALTER TABLE log_query ADD PRIMARY KEY (id);
ALTER TABLE log_query ADD CONSTRAINT queryid_timepoint_unique_key UNIQUE (queryid, timepoint );
ALTER TABLE log_query ADD CONSTRAINT query_md5hash_timepoint_unique_key UNIQUE (query_md5hash, timepoint );

CREATE INDEX log_query_timepoint_idx ON log_query (timepoint);
CREATE INDEX log_query_queryid_idx ON log_query (queryid);
ALTER TABLE log_query ADD CONSTRAINT database_id_fk FOREIGN KEY (database_id) REFERENCES database (id) ON DELETE CASCADE ;

ื”ื‘ืงืฉื” ื”ืžื ื•ืชื—ืช ืžืขื•ื‘ื“ืช ื‘ plpgsql ืคื•ื ืงืฆื™ื•ืช"log_query".
log_query.sql

--log_query.sql
--verison HABR
CREATE OR REPLACE FUNCTION log_query( ip_port text ,log_database_id integer , log_date text , log_time text , duration text , sql_line text   ) RETURNS boolean AS $$
DECLARE
  result boolean ;
  log_timepoint timestamp without time zone ;
  log_duration double precision ; 
  pos integer ;
  log_query text ;
  activity_string text ;
  log_md5hash text ;
  log_explain_plan text[] ;
  
  log_planhash text ;
  log_plan_wo_costs text[] ; 
  
  database_rec record ;
  
  pg_stat_query text ; 
  test_log_query text ;
  log_query_rec record;
  found_flag boolean;
  
  pg_stat_history_rec record ;
  port_start integer ;
  port_end integer ;
  client_ip text ;
  client_port text ;
  log_queryid bigint ;
  log_query_text text ;
  pg_stat_query_text text ; 
BEGIN
  result = TRUE ;

  RAISE NOTICE '***log_query';
  
  port_start = position('(' in ip_port);
  port_end = position(')' in ip_port);
  client_ip = substring( ip_port from 1 for port_start-1 );
  client_port = substring( ip_port from port_start+1 for port_end-port_start-1 );

  SELECT e.host , d.name , d.owner_pwd 
  INTO database_rec
  FROM database d JOIN endpoint e ON e.id = d.endpoint_id
  WHERE d.id = log_database_id ;
  
  log_timepoint = to_timestamp(log_date||' '||log_time,'YYYY-MM-DD HH24-MI-SS');
  log_duration = duration:: double precision; 

  
  pos = position ('SELECT' in UPPER(sql_line) );
  log_query = substring( sql_line from pos for LENGTH(sql_line));
  log_query = regexp_replace(log_query,' +',' ','g');
  log_query = regexp_replace(log_query,';+','','g');
  log_query = trim(trailing ' ' from log_query);
 

  log_md5hash = md5( log_query::text );
  
  --Explain execution plan--
  EXECUTE 'SELECT dblink_connect(''LINK1'',''host='||database_rec.host||' dbname='||database_rec.name||' user=DATABASE password='||database_rec.owner_pwd||' '')'; 
  
  log_explain_plan = ARRAY ( SELECT * FROM dblink('LINK1', 'EXPLAIN '||log_query ) AS t (plan text) );
  log_plan_wo_costs = ARRAY ( SELECT * FROM dblink('LINK1', 'EXPLAIN ( COSTS FALSE ) '||log_query ) AS t (plan text) );
    
  PERFORM dblink_disconnect('LINK1');
  --------------------------
  BEGIN
	INSERT INTO log_query
	(
		query_md5hash ,
		database_id , 
		timepoint ,
		duration ,
		query ,
		explained_plan ,
		plan_md5hash , 
		explained_plan_wo_costs , 
		plan_hash_value , 
		ip , 
		port
	) 
	VALUES 
	(
		log_md5hash ,
		log_database_id , 
		log_timepoint , 
		log_duration , 
		log_query ,
		log_explain_plan , 
		md5(log_explain_plan::text) ,
		log_plan_wo_costs , 
		md5(log_plan_wo_costs::text),
		client_ip , 
		client_port		
	);
	activity_string = 	'New query has logged '||
						' database_id = '|| log_database_id ||
						' query_md5hash='||log_md5hash||
						' , timepoint = '||to_char(log_timepoint,'YYYYMMDD HH24:MI:SS');
					
	RAISE NOTICE '%',activity_string;					
					 
	PERFORM pg_log( log_database_id , 'log_query' , activity_string);  

	EXCEPTION
	  WHEN unique_violation THEN
		RAISE NOTICE '*** unique_violation *** query already has logged';
	END;

	SELECT 	queryid
	INTO   	log_queryid
	FROM 	log_query 
	WHERE 	query_md5hash = log_md5hash AND
			timepoint = log_timepoint;

	IF log_queryid IS NOT NULL 
	THEN 
	  RAISE NOTICE 'log_query with query_md5hash = % and timepoint = % has already has a QUERYID = %',log_md5hash,log_timepoint , log_queryid ;
	  RETURN result;
	END IF;
	
	------------------------------------------------
	RAISE NOTICE 'Update queryid';	
	
	SELECT * 
	INTO log_query_rec
	FROM log_query
	WHERE query_md5hash = log_md5hash AND timepoint = log_timepoint ; 
	
	log_query_rec.query=regexp_replace(log_query_rec.query,';+','','g');
	
	FOR pg_stat_history_rec IN
	 SELECT 
         queryid ,
	  query 
	 FROM 
         pg_stat_db_queries 
     WHERE  
      database_id = log_database_id AND
       queryid is not null 
	LOOP
	  pg_stat_query = pg_stat_history_rec.query ; 
	  pg_stat_query=regexp_replace(pg_stat_query,'n+',' ','g');
	  pg_stat_query=regexp_replace(pg_stat_query,'t+',' ','g');
	  pg_stat_query=regexp_replace(pg_stat_query,' +',' ','g');
	  pg_stat_query=regexp_replace(pg_stat_query,'$.','%','g');
	
	  log_query_text = trim(trailing ' ' from log_query_rec.query);
	  pg_stat_query_text = pg_stat_query; 
	
	  
	  --SELECT log_query_rec.query like pg_stat_query INTO found_flag ; 
	  IF (log_query_text LIKE pg_stat_query_text) THEN
		found_flag = TRUE ;
	  ELSE
		found_flag = FALSE ;
	  END IF;	  
	  
	  
	  IF found_flag THEN
	    
		UPDATE log_query SET queryid = pg_stat_history_rec.queryid WHERE query_md5hash = log_md5hash AND timepoint = log_timepoint ;
		activity_string = 	' updated queryid = '||pg_stat_history_rec.queryid||
		                    ' for log_query with id = '||log_query_rec.id               
		   				    ;						
	    RAISE NOTICE '%',activity_string;	
		EXIT ;
	  END IF ;
	  
	END LOOP ;
	
  RETURN result ;
END
$$ LANGUAGE plpgsql;

ื‘ืขืช ืขื™ื‘ื•ื“, ื ืขืฉื” ืฉื™ืžื•ืฉ ื‘ื˜ื‘ืœืช ื”ืฉื™ืจื•ืช pg_stat_db_queriesA ืฉืžื›ื™ืœ ืชืžื•ื ืช ืžืฆื‘ ืฉืœ ื”ืฉืื™ืœืชื•ืช ื”ื ื•ื›ื—ื™ื•ืช ืžื”ื˜ื‘ืœื” pg_stat_history (ื”ืฉื™ืžื•ืฉ ื‘ื˜ื‘ืœื” ืžืชื•ืืจ ื›ืืŸ - ื ื™ื˜ื•ืจ ื‘ื™ืฆื•ืขื™ื ืฉืœ ืฉืื™ืœืชื•ืช PostgreSQL. ื—ืœืง 1 - ื“ื™ื•ื•ื—)

TABLE pg_stat_db_queries
(
   database_id integer,  
   queryid bigint ,  
   query text , 
   max_time double precision 
);

TABLE pg_stat_history 
(
โ€ฆ
database_id integer ,
โ€ฆ
queryid bigint ,
โ€ฆ
max_time double precision	 , 	
โ€ฆ
);

ื”ืคื•ื ืงืฆื™ื” ืžืืคืฉืจืช ืœืš ืœื™ื™ืฉื ืžืกืคืจ ืชื›ื•ื ื•ืช ืฉื™ืžื•ืฉื™ื•ืช ืœืขื™ื‘ื•ื“ ื‘ืงืฉื•ืช ืžืงื•ื‘ืฅ ื™ื•ืžืŸ. ื›ืœื•ืžืจ:

ื”ื–ื“ืžื ื•ืช ืžืก' 1 - ื”ื™ืกื˜ื•ืจื™ื™ืช ื‘ื™ืฆื•ืข ืฉืื™ืœืชื•ืช

ืฉื™ืžื•ืฉื™ ืžืื•ื“ ืœืชื—ื™ืœืช ืื™ืจื•ืข ื‘ื™ืฆื•ืขื™ื. ืจืืฉื™ืช, ื”ื›ื™ืจื• ืืช ื”ื”ื™ืกื˜ื•ืจื™ื” โ€“ ื•ืžืชื™ ื”ื—ืœื” ื”ื”ืื˜ื”?
ื•ืื–, ืœืคื™ ื”ืงืœืืกื™ืงื”, ื—ืคืฉ ืกื™ื‘ื•ืช ื—ื™ืฆื•ื ื™ื•ืช. ื™ื›ื•ืœ ืœื”ื™ื•ืช ืฉืขื•ืžืก ืžืกื“ ื”ื ืชื•ื ื™ื ื’ื“ืœ ื‘ืื•ืคืŸ ื“ืจืžื˜ื™ ื•ืœื‘ืงืฉื” ื”ืกืคืฆื™ืคื™ืช ืื™ืŸ ืฉื•ื ืงืฉืจ ืœื–ื”.
ื”ื•ืกืฃ ืขืจืš ื—ื“ืฉ ืœื˜ื‘ืœืช log_query

  port_start = position('(' in ip_port);
  port_end = position(')' in ip_port);
  client_ip = substring( ip_port from 1 for port_start-1 );
  client_port = substring( ip_port from port_start+1 for port_end-port_start-1 );

  SELECT e.host , d.name , d.owner_pwd 
  INTO database_rec
  FROM database d JOIN endpoint e ON e.id = d.endpoint_id
  WHERE d.id = log_database_id ;
  
  log_timepoint = to_timestamp(log_date||' '||log_time,'YYYY-MM-DD HH24-MI-SS');
  log_duration = to_number(duration,'99999999999999999999D9999999999'); 

  
  pos = position ('SELECT' in UPPER(sql_line) );
  log_query = substring( sql_line from pos for LENGTH(sql_line));
  log_query = regexp_replace(log_query,' +',' ','g');
  log_query = regexp_replace(log_query,';+','','g');
  log_query = trim(trailing ' ' from log_query);
 
  RAISE NOTICE 'log_query=%',log_query ;   

  log_md5hash = md5( log_query::text );
  
  --Explain execution plan--
  EXECUTE 'SELECT dblink_connect(''LINK1'',''host='||database_rec.host||' dbname='||database_rec.name||' user=DATABASE password='||database_rec.owner_pwd||' '')'; 
  
  log_explain_plan = ARRAY ( SELECT * FROM dblink('LINK1', 'EXPLAIN '||log_query ) AS t (plan text) );
  log_plan_wo_costs = ARRAY ( SELECT * FROM dblink('LINK1', 'EXPLAIN ( COSTS FALSE ) '||log_query ) AS t (plan text) );
    
  PERFORM dblink_disconnect('LINK1');
  --------------------------
  BEGIN
	INSERT INTO log_query
	(
		query_md5hash ,
		database_id , 
		timepoint ,
		duration ,
		query ,
		explained_plan ,
		plan_md5hash , 
		explained_plan_wo_costs , 
		plan_hash_value , 
		ip , 
		port
	) 
	VALUES 
	(
		log_md5hash ,
		log_database_id , 
		log_timepoint , 
		log_duration , 
		log_query ,
		log_explain_plan , 
		md5(log_explain_plan::text) ,
		log_plan_wo_costs , 
		md5(log_plan_wo_costs::text),
		client_ip , 
		client_port		
	);

ืชื›ื•ื ื” ืžืก' 2 - ืฉืžื•ืจ ืชื•ื›ื ื™ื•ืช ื‘ื™ืฆื•ืข ืฉืื™ืœืชื•ืช

ื‘ืฉืœื‘ ื–ื” ืขืฉื•ื™ื” ืœื”ืชืขื•ืจืจ ื”ืขืจืช-ื”ื‘ื”ืจื”-ื”ืชื ื’ื“ื•ืช: "ืื‘ืœ ื™ืฉ ื›ื‘ืจ ื”ืกื‘ืจ ืื•ื˜ื•ืžื˜ื™". ื›ืŸ, ืื‘ืœ ืžื” ื”ื˜ืขื ืื ืชื•ื›ื ื™ืช ื”ื‘ื™ืฆื•ืข ืžืื•ื—ืกื ืช ื‘ืื•ืชื• ืงื•ื‘ืฅ ื™ื•ืžืŸ ื•ื›ื“ื™ ืœืฉืžื•ืจ ืื•ืชื” ืœื ื™ืชื•ื— ื ื•ืกืฃ, ืขืœื™ืš ืœื ืชื— ืืช ืงื•ื‘ืฅ ื”ื™ื•ืžืŸ?

ืขื ื–ืืช, ื”ื™ื™ืชื™ ืฆืจื™ืš:
ืจืืฉื™ืช: ืื—ืกืŸ ืืช ืชื•ื›ื ื™ืช ื”ื‘ื™ืฆื•ืข ื‘ื˜ื‘ืœืช ื”ืฉื™ืจื•ืช ืฉืœ ืžืกื“ ื”ื ืชื•ื ื™ื ื”ื ื™ื˜ื•ืจ;
ืฉื ื™ืช: ืœื”ื™ื•ืช ืžืกื•ื’ืœื™ื ืœื”ืฉื•ื•ืช ืชื•ื›ื ื™ื•ืช ื‘ื™ืฆื•ืข ื‘ื™ื ื™ื”ืŸ ื›ื“ื™ ืœืจืื•ืช ืžื™ื“ ืฉืชื›ื ื™ืช ื‘ื™ืฆื•ืข ื”ืฉืื™ืœืชื” ื”ืฉืชื ืชื”.

ื‘ืงืฉื” ืขื ืคืจืžื˜ืจื™ ื‘ื™ืฆื•ืข ืกืคืฆื™ืคื™ื™ื ื–ืžื™ื ื”. ื”ืฉื’ืช ื•ืื—ืกื•ืŸ ืชื•ื›ื ื™ืช ื”ื‘ื™ืฆื•ืข ืฉืœื• ื‘ืืžืฆืขื•ืช EXPLAIN ื”ื™ื ืžืฉื™ืžื” ื‘ืกื™ืกื™ืช.
ื™ืชืจื” ืžื›ืš, ื‘ืืžืฆืขื•ืช ื”ื‘ื™ื˜ื•ื™ EXPLAIN (COSTS FALSE) ื ื™ืชืŸ ืœืงื‘ืœ ืืช ื”ืžืกื’ืจืช ืฉืœ ื”ืชื›ื ื™ืช, ืฉืชืฉืžืฉ ืœืงื‘ืœืช ืขืจืš ื”ื’ื™ื‘ื•ื‘ ืฉืœ ื”ืชื›ื ื™ืช, ืžื” ืฉื™ืขื–ื•ืจ ื‘ื ื™ืชื•ื— ื”ื‘ื ืฉืœ ื”ื™ืกื˜ื•ืจื™ื™ืช ื”ืฉื™ื ื•ื™ื™ื ืฉืœ ืชื›ื ื™ืช ื”ื‘ื™ืฆื•ืข.
ืงื‘ืœ ืชื‘ื ื™ืช ืชื•ื›ื ื™ืช ื‘ื™ืฆื•ืข

  --Explain execution plan--
  EXECUTE 'SELECT dblink_connect(''LINK1'',''host='||database_rec.host||' dbname='||database_rec.name||' user=DATABASE password='||database_rec.owner_pwd||' '')'; 
  
  log_explain_plan = ARRAY ( SELECT * FROM dblink('LINK1', 'EXPLAIN '||log_query ) AS t (plan text) );
  log_plan_wo_costs = ARRAY ( SELECT * FROM dblink('LINK1', 'EXPLAIN ( COSTS FALSE ) '||log_query ) AS t (plan text) );
    
  PERFORM dblink_disconnect('LINK1');

ื”ื–ื“ืžื ื•ืช ืžืก' 3 - ืฉื™ืžื•ืฉ ื‘ื™ื•ืžืŸ ื”ืฉืื™ืœืชื•ืช ืœื ื™ื˜ื•ืจ

ืžื›ื™ื•ื•ืŸ ืฉืžื“ื“ื™ ื”ื‘ื™ืฆื•ืขื™ื ืžื•ื’ื“ืจื™ื ืœื ืขื‘ื•ืจ ื˜ืงืกื˜ ื”ื‘ืงืฉื”, ืืœื ืขื‘ื•ืจ ื”ืžื–ื”ื” ืฉืœื•, ืขืœื™ืš ืœืฉื™ื™ืš ื‘ืงืฉื•ืช ืžืงื•ื‘ืฅ ื”ื™ื•ืžืŸ ืœื‘ืงืฉื•ืช ืฉืขื‘ื•ืจืŸ ืžื•ื’ื“ืจื™ื ืžื“ื“ื™ ื‘ื™ืฆื•ืขื™ื.
ื•ื‘ื›ืŸ, ืœืคื—ื•ืช ื›ื“ื™ ืœืงื‘ืœ ืืช ื”ืฉืขื” ื”ืžื“ื•ื™ืงืช ืฉืœ ื”ืชืจื—ืฉื•ืช ืฉืœ ืื™ืจื•ืข ื‘ื™ืฆื•ืข.

ืœืคื™ื›ืš, ื›ืืฉืจ ืžืชืจื—ืฉ ืื™ืจื•ืข ื‘ื™ืฆื•ืข ืขื‘ื•ืจ ืžื–ื”ื” ื‘ืงืฉื”, ื™ื”ื™ื” ืงื™ืฉื•ืจ ืœื‘ืงืฉื” ืกืคืฆื™ืคื™ืช ืขื ืขืจื›ื™ ืคืจืžื˜ืจ ืกืคืฆื™ืคื™ื™ื ื•ื–ืžืŸ ื”ื‘ื™ืฆื•ืข ื”ืžื“ื•ื™ืง ื•ืžืฉืš ื”ื‘ืงืฉื”. ืงื‘ืœ ืืช ื”ืžื™ื“ืข ื”ื ืชื•ืŸ ื‘ืืžืฆืขื•ืช ื”ืชืฆื•ื’ื” ื‘ืœื‘ื“ pg_stat_statements - ื–ื” ืืกื•ืจ.
ืžืฆื ืืช ื”-queryid ืฉืœ ื”ืฉืื™ืœืชื” ื•ืขื“ื›ืŸ ืืช ื”ืขืจืš ื‘ื˜ื‘ืœืช log_query

SELECT * 
	INTO log_query_rec
	FROM log_query
	WHERE query_md5hash = log_md5hash AND timepoint = log_timepoint ; 
	
	log_query_rec.query=regexp_replace(log_query_rec.query,';+','','g');
	
	FOR pg_stat_history_rec IN
	 SELECT 
      queryid ,
	  query 
	 FROM 
       pg_stat_db_queries 
     WHERE  
	   database_id = log_database_id AND
       queryid is not null 
	LOOP
	  pg_stat_query = pg_stat_history_rec.query ; 
	  pg_stat_query=regexp_replace(pg_stat_query,'n+',' ','g');
	  pg_stat_query=regexp_replace(pg_stat_query,'t+',' ','g');
	  pg_stat_query=regexp_replace(pg_stat_query,' +',' ','g');
	  pg_stat_query=regexp_replace(pg_stat_query,'$.','%','g');
	
	  log_query_text = trim(trailing ' ' from log_query_rec.query);
	  pg_stat_query_text = pg_stat_query; 
	  
	  --SELECT log_query_rec.query like pg_stat_query INTO found_flag ; 
	  IF (log_query_text LIKE pg_stat_query_text) THEN
		found_flag = TRUE ;
	  ELSE
		found_flag = FALSE ;
	  END IF;	  
	  
	  
	  IF found_flag THEN
	    
		UPDATE log_query SET queryid = pg_stat_history_rec.queryid WHERE query_md5hash = log_md5hash AND timepoint = log_timepoint ;
		activity_string = 	' updated queryid = '||pg_stat_history_rec.queryid||
		                    ' for log_query with id = '||log_query_rec.id		                    
		   				    ;						
					
	    RAISE NOTICE '%',activity_string;	
		EXIT ;
	  END IF ;
	  
	END LOOP ;

ืื—ืจื™ืช ื“ื‘ืจ

ื›ืชื•ืฆืื” ืžื›ืš, ื”ืฉื™ื˜ื” ื”ืžืชื•ืืจืช ืžืฆืื” ืืช ื”ื™ื™ืฉื•ื ืฉืœื” ื‘ ืฉืคื•ืชื—ื” ืžืขืจื›ืช ืœื ื™ื˜ื•ืจ ื”ื‘ื™ืฆื•ืขื™ื ืฉืœ ืฉืื™ืœืชื•ืช PostgreSQL, ืžื” ืฉืžืืคืฉืจ ืœืš ืœืงื‘ืœ ืžื™ื“ืข ื ื•ืกืฃ ืœื ื™ืชื•ื— ื‘ืขืช ืคืชืจื•ืŸ ืื™ืจื•ืขื™ ื‘ื™ืฆื•ืขื™ ืฉืื™ืœืชื•ืช ืžืชืขื•ืจืจื™ื.

ืื ื›ื™, ื›ืžื•ื‘ืŸ, ืœื“ืขืชื™ ื”ืื™ืฉื™ืช, ืขื“ื™ื™ืŸ ื™ื”ื™ื” ืฆื•ืจืš ืœืขื‘ื•ื“ ืขืœ ื”ืืœื’ื•ืจื™ืชื ืœื‘ื—ื™ืจื” ื•ืฉื™ื ื•ื™ ื’ื•ื“ืœ ื”ื—ืœืง ืฉื”ื•ืจื“. ื”ื‘ืขื™ื” ื˜ืจื ื ืคืชืจื” ื‘ืžืงืจื” ื”ื›ืœืœื™. ื–ื” ื›ื ืจืื” ื™ื”ื™ื” ืžืขื ื™ื™ืŸ.

ืื‘ืœ ื–ื” ืกื™ืคื•ืจ ืื—ืจ ืœื’ืžืจื™...

ืžืงื•ืจ: www.habr.com

ื”ื•ืกืคืช ืชื’ื•ื‘ื”