Após criar a rotina de VACUUM controlando o tempo de execução, post anterior, pensei em como poderia aplicar este método na manutenção dos índices de uma determinada base. Então as perguntas iniciais foram:
1 - O que eu queria com isso?
Precisava de uma rotina que realizasse a manutenção dos índices mais inchados da base, sendo que devido ao curto espaço de tempo disponível para a execução desta rotina, a mesma precisaria atingir as tabelas mais críticas da base.
2 - O que não poderia acontecer com isso?
- A rotina afetar a produção ou carga durante a produção;
- A rotina remover algum índice ativo;
- Prejudicar o plano de execução da base;
- Comprometer outra rotina de manutenção;
Com o risco calculado e um bom ambiente de homologação, foi criada uma rotina de reindexação que avalia o inchaço dos índices não PK das 15 tabelas com mais atualizações e exclusões de registros. Em resumo a rotina obtêm a DDL destes índices e um a um cria um índice temporário, após deleta o índice inchado e ao término atualiza as estatísticas destas tabelas.
Como o processo é transacional, como temos um controle de tempo(exemplo timeout é 6 horas da manhã) caso este controle de tempo mate a criação de índice o índice ainda inchado não é afetado.
Requisitos:
1 - A base alvo deve possuir a VIEW abaixo:
CREATE OR REPLACE VIEW bloat_objects AS
SELECT current_database() AS current_database, sml.schemaname, sml.tablename, sml.reltuples::bigint AS reltuples, sml.relpages::bigint AS relpages, sml.otta, round(
CASE
WHEN sml.otta = 0::double precision THEN 0.0
ELSE sml.relpages::numeric / sml.otta::numeric
END, 1) AS tbloat,
CASE
WHEN sml.relpages::double precision < sml.otta THEN 0::double precision
ELSE sml.relpages::bigint::double precision - sml.otta
END AS wastedpages,
CASE
WHEN sml.relpages::double precision < sml.otta THEN 0::numeric
ELSE sml.bs * (sml.relpages::double precision - sml.otta)::bigint::numeric
END AS wastedbytes,
CASE
WHEN sml.relpages::double precision < sml.otta THEN '0 bytes'::text
ELSE (sml.bs::double precision * (sml.relpages::double precision - sml.otta))::bigint || ' bytes'::text
END AS wastedsize, sml.iname, sml.ituples::bigint AS ituples, sml.ipages::bigint AS ipages, sml.iotta, round(
CASE
WHEN sml.iotta = 0::double precision OR sml.ipages = 0 THEN 0.0
ELSE sml.ipages::numeric / sml.iotta::numeric
END, 1) AS ibloat, round(
CASE
WHEN sml.iotta = 0::double precision OR sml.ipages = 0 THEN 0.0
ELSE sml.ipages::numeric / sml.iotta::numeric
END, 1) * 100::numeric AS perc_ibloat,
CASE
WHEN sml.ipages::double precision < sml.iotta THEN 0::double precision
ELSE sml.ipages::bigint::double precision - sml.iotta
END AS wastedipages,
CASE
WHEN sml.ipages::double precision < sml.iotta THEN 0::double precision
ELSE sml.bs::double precision * (sml.ipages::double precision - sml.iotta)
END AS wastedibytes,
CASE
WHEN sml.ipages::double precision < sml.iotta THEN '0 bytes'::text
ELSE (sml.bs::double precision * (sml.ipages::double precision - sml.iotta))::bigint || ' bytes'::text
END AS wastedisize
FROM ( SELECT rs.schemaname, rs.tablename, cc.reltuples, cc.relpages, rs.bs, ceil(cc.reltuples * ((rs.datahdr + rs.ma::numeric -
CASE
WHEN (rs.datahdr % rs.ma::numeric) = 0::numeric THEN rs.ma::numeric
ELSE rs.datahdr % rs.ma::numeric
END)::double precision + rs.nullhdr2 + 4::double precision) / (rs.bs::double precision - 20::double precision)) AS otta, COALESCE(c2.relname, '?'::name) AS iname, COALESCE(c2.reltuples, 0::real) AS ituples, COALESCE(c2.relpages, 0) AS ipages, COALESCE(ceil(c2.reltuples * (rs.datahdr - 12::numeric)::double precision / (rs.bs::double precision - 20::double precision)), 0::double precision) AS iotta
FROM ( SELECT foo.ma, foo.bs, foo.schemaname, foo.tablename, (foo.datawidth + (foo.hdr + foo.ma -
CASE
WHEN (foo.hdr % foo.ma) = 0 THEN foo.ma
ELSE foo.hdr % foo.ma
END)::double precision)::numeric AS datahdr, foo.maxfracsum * (foo.nullhdr + foo.ma -
CASE
WHEN (foo.nullhdr % foo.ma::bigint) = 0 THEN foo.ma::bigint
ELSE foo.nullhdr % foo.ma::bigint
END)::double precision AS nullhdr2
FROM ( SELECT s.schemaname, s.tablename, constants.hdr, constants.ma, constants.bs, sum((1::double precision - s.null_frac) * s.avg_width::double precision) AS datawidth, max(s.null_frac) AS maxfracsum, constants.hdr + (( SELECT 1 + count(*) / 8
FROM pg_stats s2
WHERE s2.null_frac <> 0::double precision AND s2.schemaname = s.schemaname AND s2.tablename = s.tablename)) AS nullhdr
FROM pg_stats s, ( SELECT ( SELECT current_setting('block_size'::text)::numeric AS current_setting) AS bs,
CASE
WHEN "substring"(foo.v, 12, 3) = ANY (ARRAY['8.0'::text, '8.1'::text, '8.2'::text]) THEN 27
ELSE 23
END AS hdr,
CASE
WHEN foo.v ~ 'mingw32'::text THEN 8
ELSE 4
END AS ma
FROM ( SELECT version() AS v) foo) constants
GROUP BY s.schemaname, s.tablename, constants.hdr, constants.ma, constants.bs) foo) rs
JOIN pg_class cc ON cc.relname = rs.tablename
JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname = rs.schemaname AND nn.nspname <> 'information_schema'::name
LEFT JOIN pg_index i ON i.indrelid = cc.oid
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid) sml
ORDER BY
CASE
WHEN sml.relpages::double precision < sml.otta THEN 0::numeric
ELSE sml.bs * (sml.relpages::double precision - sml.otta)::bigint::numeric
END DESC;
ALTER TABLE bloat_objects
OWNER TO postgres;
Estrutura da rotina:
1 - O path deve ser ajustado dentro da rotina para o path que utilizará;
2 - Deves criar dentro deste path as pastas: bin / log / var / lib / tmp.
Abaixo a rotina de reindexação(crie dentro do 'bin' com o nome 'reindex-maintenance-pgsql.pl'):
#!/usr/bin/perl
#reindex-maintenance-pgsql
#
#Description: Rotina de manutenção de REINDEX para o PostgreSQL
#
#Author:
# Gabriel Prestes (helkmut@gmail.com)
#
#07-31-2013 : Created
use strict;
use Getopt::Long;
use POSIX;
use File::Basename;
use warnings;
#--------------------------------------------------
# Setting environment
#--------------------------------------------------
$ENV{"USER"}="root";
$ENV{"HOME"}="/root";
#--------------------------------------------------
# Global variables
#--------------------------------------------------
our $name = basename($0);
our $version = "1.2";
our $opt_path = "/opt/resources/reindex-maintenance-pgsql";
our $log_date = `/bin/date -I`;
chomp($log_date);
our $temp_log = "$opt_path/log/reindex-maintenance-pgsql-$log_date.log";
our $opt_props = "$opt_path/lib/maindb.props";
our ($opt_help, $opt_verbose, $opt_version);
#--------------------------------------------------
# Program variables
#--------------------------------------------------
#--------------------------------------------------
# Prop variables
#--------------------------------------------------
our $opt_pguser;
our $opt_pgport;
our $opt_pgdb;
our $opt_owner;
our $opt_fim;
#--------------------------------------------------------------------------------------
sub main {
# --- Get Options --- #
getoption();
# --- Init function vars ---#
my $counter = 0;
my $flagcontrol=0;
my $rows=0;
my $sqlquery;
my $cmd;
my @prop_split=();
my @props_array=();
my @tables=();
my @sqlcmd = ();
# --- Verbose ---#
logger("|PROGRAM OUT: Init agent|");
# --- Get props program --- #
open (PROPS, "$opt_props") or error();
@props_array = ;
close(PROPS);
foreach(@props_array){
chomp($_);
@prop_split = split(/=/,$_);
if($counter == 0){$opt_pguser = $prop_split[1];}
if($counter == 1){$opt_pgport = $prop_split[1];}
if($counter == 2){$opt_pgdb = $prop_split[1];}
if($counter == 3){$opt_owner = $prop_split[1];}
if($counter == 4){$opt_fim = $prop_split[1];}
$counter++;
}
$counter=0;
# --- Check and write pid --- #
if(check_pid() == 0){
logger("|PROGRAM OUT: Another job in execution($opt_path/var/reindex-maintenance-pgsql.pid)|");
exit(1);
} else {
write_pid();
}
# --- Rotate logs more than 15 days --- #
logger("|PROGRAM OUT: LOGs - Search for more than 15 days old|");
$cmd=`\$\(which find\) $opt_path/log/* -name "*" -mtime +15 -exec \$\(which rm\) -rf {} \\; > /dev/null 2>&1`;
# --- Get relations to reindex --- #
logger("|PROGRAM OUT: Obtendo relacao de tabelas mais utilizadas com indices inchados|");
$sqlquery = "SELECT DISTINCT ON (tablename) tablename FROM bloat_objects WHERE (tablename IN ( SELECT relname FROM pg_stat_user_tables WHERE (n_tup_upd+n_tup_del) > 0 ORDER BY (n_tup_upd+n_tup_del) DESC LIMIT 30 )) AND perc_ibloat > 50::numeric ORDER BY tablename, perc_ibloat DESC;";
@sqlcmd = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"$sqlquery\"`;
$flagcontrol+=$?;
if($flagcontrol>0){
logger("|PROGRAM OUT: Nao pode obter lista de tabelas : falha de comunicacao com a instancia|");
exit_program();
}
# --- Mount tables in array --- #
foreach(@sqlcmd){
chomp($_);
if($_ =~ m/^ (.+)$/g){
push(@tables,$1);
}
if($_ =~ m/^\((.+) row.+$/){
$rows=$1;
}
}
my @sqlcmdaux = ();
my $sqlindexquery;
my $sqlin;
my $sqlindexpart1;
my $sqlindexpart2;
my $sqlindexpart3;
my $sqlindexpartnew = "idx_temp_maintenance";
trim($rows);
if(@tables){
foreach(@tables){
chomp($_);
trim($_);
if($_ !~ "tablename"){
logger("|PROGRAM OUT: A tabela '$_' sera reindexada|");
foreach(@tables){
chomp($_);
$sqlin .= "\'$_\',";
}
chop($sqlin);
}
}
}
logger("|PROGRAM OUT: $rows tabelas para reindexar|");
if($rows==0){
logger("|PROGRAM OUT: OK - Rotina de reindexacao realizada com sucesso!|");
exit_program();
}
my $time=`/bin/date +%H`;
my $indexcount=0;
chomp($time);
# --- Build REINDEX command --- #
logger("|PROGRAM OUT: Montando vetor de tabelas...|");
logger("|PROGRAM OUT: Obtendo relacao de indices...|");
$sqlquery = "SELECT REPLACE(Pg_get_indexdef(i.oid), 'INDEX ', 'INDEX CONCURRENTLY ') || ';' FROM pg_index x JOIN pg_class c ON c.oid = x.indrelid JOIN pg_class i ON i.oid = x.indexrelid LEFT JOIN pg_namespace n ON n.oid = c.relnamespace LEFT JOIN pg_tablespace t ON t.oid = i.reltablespace WHERE c.relkind = 'r'::\"char\" AND i.relkind = 'i'::\"char\" AND indisprimary IS FALSE AND c.relname IN($sqlin);";
@sqlcmd = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"$sqlquery\"`;
logger("|PROGRAM OUT: Retorno de DDL criacao dos indices:|");
foreach(@sqlcmd){
chomp($_);
logger("$_");
}
# --- Drop idx_temp_maintenance if exists --- #
logger("|PROGRAM OUT: Drop $sqlindexpartnew if exists|");
@sqlcmdaux = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"DROP INDEX IF EXISTS $sqlindexpartnew\"`;
$flagcontrol += $?;
# --- Run reindex --- #
foreach(@sqlcmd){
$sqlindexquery = "";
$sqlindexquery = $_;
if($sqlindexquery =~ m/^ (CREATE.+CONCURRENTLY) (.+) (ON.+)$/){
$sqlindexpart1=$1;
$sqlindexpart2=$2;
$sqlindexpart3=$3;
# --- Time check --- #
$time=`/bin/date +%H`;
chomp($time);
if($time>=$opt_fim){
logger("|PROGRAM OUT: Recriacao do indice abortado em funcao do horario: $time|");
next;
} else {
logger("|PROGRAM OUT: Horario verificado nao excede gatilho: $time|");
$indexcount++;
}
logger("|PROGRAM OUT: Recriando indice: $sqlindexpart2|");
logger("$sqlindexpart1 $sqlindexpartnew $sqlindexpart3");
@sqlcmdaux = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"$sqlindexpart1 $sqlindexpartnew $sqlindexpart3\"`;
$flagcontrol += $?;
if($flagcontrol>0){next;}
logger("DROP INDEX $sqlindexpart2;");
@sqlcmdaux = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"BEGIN;DROP INDEX $sqlindexpart2;ALTER INDEX $sqlindexpartnew RENAME TO $sqlindexpart2;ALTER INDEX $sqlindexpart2 OWNER TO $opt_owner;COMMIT;\"`;
$flagcontrol += $?;
}
}
if($indexcount==0){
logger("|PROGRAM OUT: ALERTA - Rotina abortada em funcao do horario: $time|");
exit_program();
}
# --- ANALYZE tables --- #
foreach(@tables){
trim($_);
if($_ !~ "tablename"){
chomp($_);
logger("|PROGRAM OUT: Atualizando as estatisticas da tabela '$_'|");
@sqlcmdaux = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"ANALYZE $_;\"`;
$flagcontrol += $?;
}
}
# ---> Avaliar necessidade de resetar estatísticas da base
# logger("|PROGRAM OUT: Resetando as estatisticas da base|");
# @sqlcmdaux = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"SELECT pg_stat_reset();\"`;
# $flagcontrol += $?;
# --- Threshoulds --- #
if($flagcontrol>0){
logger("|PROGRAM OUT: ERRO - Rotina de reindexacao finalizou com erros($flagcontrol) verifique o mais rapido possivel|");
} else {
logger("|PROGRAM OUT: OK - Rotina de reindexacao realizada com sucesso!|");
}
exit_program();
}
#--------------------------------------------------------------------------------------
sub getoption {
Getopt::Long::Configure('bundling');
GetOptions(
'V|version' => \$opt_version,
'h|help' => \$opt_help,
'v|verbose=i' => \$opt_verbose,
);
if($opt_help){
printHelp();
exit_program();
}
if($opt_version){
print "$name - '$version'\n";
exit_program();
}
}
#--------------------------------------------------------------------------------------
sub logger {
return(0) if (not defined $opt_verbose);
my $msg = shift (@_);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
$wday++;
$yday++;
$mon++;
$year+=1900;
$isdst++;
if ($opt_verbose == 0){
print "$msg\n";
} else {
open(LOG, ">>$temp_log") or error();
printf LOG ("%02i/%02i/%i - %02i:%02i:%02i => %s\n",$mday,$mon,$year,$hour,$min,$sec,$msg);
close(LOG);
}
}
#--------------------------------------------------------------------------------------
sub printHelp {
my $help = <<'HELP';
Thanks for use Reindex Maintenance PGSQL.
API required:
strict;
Getopt::Long;
POSIX;
File::Basename;
warnings;
Agent binary : bin/reindex-maintenance-pgsql.pl &
Configuration Agent in : lib/maindb.props
Support : helkmut@gmail.com
Salmo 91:
"Direi do Senhor: Não temerás os terrores da noite, nem a seta que voe de dia, nem peste que anda na escuridão, nem mortandade que assole ao meio-dia."
HELP
system("clear");
print $help;
}
#--------------------------------------------------------------------------------------
sub error {
print "|ERROR - Unexpected return - contact support|\n";
exit_program();
}
#--------------------------------------------------------------------------------------
sub trim($) {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
#--------------------------------------------------------------------------------------
sub write_pid {
my $cmd;
$cmd=`\$\(which touch\) $opt_path/var/reindex-maintenance-pgsql.pid`;
return 1;
}
#--------------------------------------------------------------------------------------
sub check_pid {
if(-e "$opt_path/var/reindex-maintenance-pgsql.pid"){
return 0;
} else {
return 1;
}
}
#--------------------------------------------------------------------------------------
sub exit_program {
my $cmd;
$cmd=`\$\(which rm\) -rf $opt_path/var/reindex-maintenance-pgsql.pid`;
exit;
}
#--------------------------------------------------------------------------------------
&main
##Ignore o '' se existir no final, é um erro de formatação do post.
Arquivo de configuração(crie dentro do 'lib' com o nome 'maindb.props'):
opt_pguser=postgres
opt_pgport=5432
opt_pgdb=postgres
opt_owner=postgres
opt_fim=06
# --- Additional info --- #
opt_pguser - > Login role
opt_pgport -> Instance port
opt_pgdb -> Database connect
opt_owner -> Owner index
opt_fim -> Time abort
# --- Additional info --- #
Arquivo de controle de tempo(crie dentro do 'bin' com nome 'reindex-controltime-pgsql.pl'):
#!/usr/bin/perl
#reindex-controltime-pgsql
#
#Description: Rotina de controle de manutenção de REINDEX para o PostgreSQL
#
#Author:
# Gabriel Prestes (helkmut@gmail.com)
#
#08-09-2013 : Created
use strict;
use Getopt::Long;
use POSIX;
use File::Basename;
use warnings;
#--------------------------------------------------
# Setting environment
#--------------------------------------------------
$ENV{"USER"}="root";
$ENV{"HOME"}="/root";
#--------------------------------------------------
# Global variables
#--------------------------------------------------
our $name = basename($0);
our $version = "0.1";
our $opt_path = "/opt/resources/reindex-maintenance-pgsql";
our $log_date = `/bin/date -I`;
chomp($log_date);
our $temp_log = "$opt_path/log/reindex-controltime-pgsql-$log_date.log";
our $opt_props = "$opt_path/lib/maindb.props";
our ($opt_help, $opt_verbose, $opt_version);
#--------------------------------------------------
# Program variables
#--------------------------------------------------
#--------------------------------------------------
# Prop variables
#--------------------------------------------------
our $opt_pguser;
our $opt_pgport;
our $opt_pgdb;
our $opt_fim;
#--------------------------------------------------------------------------------------
sub main {
# --- Get Options --- #
getoption();
# --- Init function vars ---#
my $counter = 0;
my $flagcontrol=0;
my $rows=0;
my $sqlquery;
my $cmd;
my @prop_split=();
my @props_array=();
my @command=();
my @sqlcmd = ();
# --- Verbose ---#
logger("|PROGRAM OUT: Init agent|");
# --- Get props program --- #
open (PROPS, "$opt_props") or error();
@props_array = ;
close(PROPS);
foreach(@props_array){
chomp($_);
@prop_split = split(/=/,$_);
if($counter == 0){$opt_pguser = $prop_split[1];}
if($counter == 1){$opt_pgport = $prop_split[1];}
if($counter == 2){$opt_pgdb = $prop_split[1];}
if($counter == 4){$opt_fim = $prop_split[1];}
$counter++;
}
$counter=0;
# --- Check and write pid --- #
if(check_pid() == 0){
logger("|PROGRAM OUT: Another job in execution($opt_path/var/reindex-controltime-pgsql.pid)|");
exit(1);
} else {
write_pid();
}
# --- Rotate logs more than 15 days --- #
logger("|PROGRAM OUT: LOGs - Search for more than 15 days old|");
$cmd=`\$\(which find\) $opt_path/log/* -name "*" -mtime +15 -exec \$\(which rm\) -rf {} \\; > /dev/null 2>&1`;
# --- Get relations to reindex --- #
logger("|PROGRAM OUT: Obtendo relacao de reindex em execucao|");
$sqlquery = "SELECT pg_stat_activity.procpid as processo FROM pg_stat_activity WHERE pg_stat_activity.current_query LIKE 'CREATE INDEX CONCURRENTLY idx_temp_maintenance%';";
@sqlcmd = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"$sqlquery\"`;
$flagcontrol+=$?;
if($flagcontrol>0){
logger("|PROGRAM OUT: Nao pode obter lista de indices : falha de comunicacao com a instancia|");
exit_program();
}
# --- Mount tables in array --- #
foreach(@sqlcmd){
chomp($_);
if($_ =~ m/^ (.+)$/g){
push(@command,$1);
}
if($_ =~ m/^\((.+) row.+$/){
$rows=$1;
}
}
my @sqlcmdaux = ();
trim($rows);
if(@command){
foreach(@command){
chomp($_);
if($_ !~ m/^proces.+$/){
trim($_);
logger("|PROGRAM OUT: O processo$_ de recriacao do indice sera cancelado|");
@sqlcmd = `/usr/bin/psql -U $opt_pguser -p $opt_pgport $opt_pgdb -q -c \"SELECT pg_cancel_backend($_)\"`;
}
}
}
logger("|PROGRAM OUT: $rows reindex cancelado(s)|");
if($rows==0){
logger("|PROGRAM OUT: OK - Rotina de controle finalizada sem cancelamento de backends!|");
exit_program();
}
# --- Threshoulds --- #
logger("|PROGRAM OUT: OK - Rotina de controle finalizada com sucesso!|");
exit_program();
}
#--------------------------------------------------------------------------------------
sub getoption {
Getopt::Long::Configure('bundling');
GetOptions(
'V|version' => \$opt_version,
'h|help' => \$opt_help,
'v|verbose=i' => \$opt_verbose,
);
if($opt_help){
printHelp();
exit_program();
}
if($opt_version){
print "$name - '$version'\n";
exit_program();
}
}
#--------------------------------------------------------------------------------------
sub logger {
return(0) if (not defined $opt_verbose);
my $msg = shift (@_);
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
$wday++;
$yday++;
$mon++;
$year+=1900;
$isdst++;
if ($opt_verbose == 0){
print "$msg\n";
} else {
open(LOG, ">>$temp_log") or error();
printf LOG ("%02i/%02i/%i - %02i:%02i:%02i => %s\n",$mday,$mon,$year,$hour,$min,$sec,$msg);
close(LOG);
}
}
#--------------------------------------------------------------------------------------
sub printHelp {
my $help = <<'HELP';
Thanks for use Reindex Controltime PGSQL.
API required:
strict;
Getopt::Long;
POSIX;
File::Basename;
warnings;
Agent binary : bin/reindex-controltime-pgsql.pl &
Configuration Agent in : lib/maindb.props
Support : helkmut@gmail.com
"Cordeiro de Deus, retirai os pecados do mundo, tende piedade de nós!"
HELP
system("clear");
print $help;
}
#--------------------------------------------------------------------------------------
sub error {
print "|ERROR - Unexpected return - contact support|\n";
exit_program();
}
#--------------------------------------------------------------------------------------
sub trim($) {
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
#--------------------------------------------------------------------------------------
sub write_pid {
my $cmd;
$cmd=`\$\(which touch\) $opt_path/var/reindex-controltime-pgsql.pid`;
return 1;
}
#--------------------------------------------------------------------------------------
sub check_pid {
if(-e "$opt_path/var/reindex-controltime-pgsql.pid"){
return 0;
} else {
return 1;
}
}
#--------------------------------------------------------------------------------------
sub exit_program {
my $cmd;
$cmd=`\$\(which rm\) -rf $opt_path/var/reindex-controltime-pgsql.pid`;
exit;
}
#--------------------------------------------------------------------------------------
&main
##Ignore o '' se existir no final, é um erro de formatação do post.
Feito isto, precisarás de dois jobs no crontab ou no pgAgent, o da rotina de reindexação que deve por exemplo iniciar meia-noite e outro job com o controle de execução que deve ser agendado para o horário em que quer abortar a rotina, exemplo 6 horas da manhã.
Exemplo de execução no pgAgent:
1 - Crie um job do tipo manutenção que executará um 'BATCH' e não 'SQL';
2 - Agende para a data e horário desejado;
3 - Na definição do passo coloque '/opt/resources/reindex-maintenance-pgsql/bin/reindex-controltime-pgsql.pl -v 1';
Faça a mesma ação para o outro job de reindexação, deixando a definição como '/opt/resources/reindex-maintenance-pgsql/bin/reindex-maintenance-pgsql.pl -v 1'.
Explicação sobre os parâmetros de configuração:
opt_pguser=postgres -> Usuário do PostgreSQL que executará a rotina
opt_pgport=5432 -> Porta da instância
opt_pgdb=postgres -> Database da instância onde a rotina será executada
opt_owner=postgres -> Dono dos índices recriados na rotina
opt_fim=06 -> Tempo estabelecido para finalizar a rotina
Então você se pergunta:
Porque um programa auxiliar para terminar a rotina de reindexação se a mesma já possui este controle internamente?
A resposta será, caso a rotina esteja criando um índice a mesma continuará em execução até finalizar essa criação, com o programa auxiliar o backend onde a criação está ocorrendo é cancelado e o índice temporário que está sendo criado é invalidado.
Análise da rotina:
Um log exemplo de execução da rotina abaixo. Lembrando que os logs já são rotacionados, mantendo somente os últimos 15 dias.
Controle de execução:
20/08/2013 - 06:30:01 => |PROGRAM OUT: Init agent|
20/08/2013 - 06:30:01 => |PROGRAM OUT: LOGs - Search for more than 15 days old|
20/08/2013 - 06:30:01 => |PROGRAM OUT: Obtendo relacao de reindex em execucao|
20/08/2013 - 06:30:01 => |PROGRAM OUT: 0 reindex cancelado(s)|
20/08/2013 - 06:30:01 => |PROGRAM OUT: OK - Rotina de controle finalizada sem cancelamento de backends!|
Rotina de reindexação:
17/08/2013 - 00:01:03 => |PROGRAM OUT: Init agent|
17/08/2013 - 00:01:03 => |PROGRAM OUT: LOGs - Search for more than 15 days old|
17/08/2013 - 00:01:03 => |PROGRAM OUT: Obtendo relacao de tabelas mais utilizadas com indices inchados|
17/08/2013 - 00:01:03 => |PROGRAM OUT: A tabela 'teste' sera reindexada|
17/08/2013 - 00:01:03 => |PROGRAM OUT: 1 tabelas para reindexar|
17/08/2013 - 00:01:03 => |PROGRAM OUT: Montando vetor de tabelas...|
17/08/2013 - 00:01:03 => |PROGRAM OUT: Obtendo relacao de indices...|
17/08/2013 - 00:01:03 => |PROGRAM OUT: Retorno de DDL criacao dos indices:|
17/08/2013 - 00:01:03 => ?column?
17/08/2013 - 00:01:03 => -------------------------------------------------------------------------------------------------------------------------------
17/08/2013 - 00:01:03 => CREATE INDEX CONCURRENTLY idx_teste_cli ON teste USING btree (cli);
17/08/2013 - 00:01:03 => CREATE INDEX CONCURRENTLY idx_teste_clo ON teste USING btree (clo);
17/08/2013 - 00:01:03 => (2 rows)
17/08/2013 - 00:01:03 =>
17/08/2013 - 00:01:03 => |PROGRAM OUT: Drop idx_temp_maintenance if exists|
17/08/2013 - 00:01:03 => |PROGRAM OUT: Horario verificado nao excede gatilho: 00|
17/08/2013 - 00:01:03 => |PROGRAM OUT: Recriando indice: idx_teste_cli |
17/08/2013 - 00:01:03 => CREATE INDEX CONCURRENTLY idx_temp_maintenance ON teste USING btree (cli);
17/08/2013 - 00:02:03 => DROP INDEX idx_teste_cli;
17/08/2013 - 00:02:04 => |PROGRAM OUT: Horario verificado nao excede gatilho: 00|
17/08/2013 - 00:02:04 => |PROGRAM OUT: Recriando indice: idx_teste_clo |
17/08/2013 - 00:02:04 => CREATE INDEX CONCURRENTLY idx_temp_maintenance ON teste USING btree (clo);
17/08/2013 - 00:02:06 => DROP INDEX idx_teste_clo ;
17/08/2013 - 00:02:24 => |PROGRAM OUT: Atualizando as estatisticas da tabela 'teste'|
17/08/2013 - 00:02:45 => |PROGRAM OUT: Resetando as estatisticas da base|
17/08/2013 - 00:02:45 => |PROGRAM OUT: OK - Rotina de reindexacao realizada com sucesso!|