前两天腾出点时间,打算整理一下POSTGRESQL 公司的数据库的无用的索引的问题,写了一个SQL 通过SQL 来获取这些数据库的无用索引,但头疼的是,我们整个TEAM 到来的时候,很多坏习惯已经养成了,所以我们目前就是在一个治标的过程,看上去我们的工作有点,“幼稚”,但谁让那些开发的部分必须让我们先改变他们的幼稚。
然后我们的一个同事,刚刚,发现了工作中的难点,并进行了超级改进,将整体的工作自动化,而且还是一个成本很低的方案,SHELL ,我知道,说起SHELL 很多人不屑,现在都是PYTHON, GO 的天下,谁还用SHELL。下面我就展示一下这个SHELL 的 功底,以及设计结构。
POSTGRESQL 的基础,这里是几十个POSTGRESQL 的实例,每个实例下面有不固定的数据库,每个数据库有几百张表,同时每张表里面有众多的没有被使用过的索引。
结果如下,会根据每个命令的执行时间,以及数据库的名字建立文件夹,然后开始针对每一个数据库进行扫描,并产生无用索引的记录以及清理和回滚的语句。
下图信息字符已经替换或更改
整体的工作量大幅度削减。
下面是整体的数据库中获取无用索引的层次图
整体的SHELL 的设计中,大致的结构如下图
SELECT s.schemaname,
s.relname AS tablename,
s.indexrelname AS indexname,
s.idx_scan,
s.idx_tup_fetch,
x.indexdef || ' ;' as index_create_statement,
pg_size_pretty(pg_relation_size(s.indexrelid)) AS index_size,
'drop index ' || s.indexrelname || ' on ' || s.relname || ' ;' as del_statement
FROM pg_catalog.pg_stat_user_indexes s
JOIN pg_catalog.pg_index i ON s.indexrelid = i.indexrelid
JOIN pg_indexes as x on x.indexname = s.indexrelname
WHERE s.idx_scan = 0
and s.idx_tup_fetch = 0
AND 0 <> ALL(i.indkey)
AND NOT i.indisunique
AND NOT EXISTS (SELECT 1
FROM pg_catalog.pg_constraint c
WHERE c.conindid = s.indexrelid)
AND NOT EXISTS (SELECT 1
FROM pg_catalog.pg_inherits AS inh
WHERE inh.inhrelid = s.indexrelid)
ORDER BY pg_relation_size(s.indexrelid) DESC;
——————————————————————————————
#!/bin/bash
hosts=/data/pg_batch_script/hosts_cy
xjsql=/data/pg_batch_script/pgindex.sql
dt=$(date '+%Y%m%d')
xudir=/data/pg_batch_script/${dt}_pgindex
if [ ! -d $xudir ]; then
mkdir -p $xudir
fi
log=/data/pg_batch_script/${dt}_pgindex/${dt}.log
#sqlFile=$3
function getDbs(){
local res=$(echo $sql |psql -h $host -p $port -U $user -d $defaultDb -At -v -w)
echo $res
}
function getTime(){
local res=$(date '+%Y%m%d_%H:%M:%S')
echo $res
}
function printLog(){
local res="$(getTime)\t$*"
echo -e $res
echo -e $res >> $log
}
function getDbInfo(){
#echo enter getDbInfo:$1
host=$(jq ".${1}.host" $hosts | sed 's/\"//g')
#echo host:$host
port=$(jq ".${1}.port" $hosts)
user=$(jq ".${1}.user" $hosts | sed 's/\"//g')
pass=$(jq ".${1}.pass" $hosts | sed 's/\"//g')
defaultDb=$(jq ".${1}.defaultdb" $hosts | sed 's/\"//g')
export PGPASSWORD=$pass
#echo getDbInfo:$host,$port,$user,$pass
}
function getSingleDefault(){
instanceName=$1
getDbInfo $instanceName
psql -h $host -p $port -U $user -d $defaultDb -w -f $xjsql > ${xudir}/${instanceName}_${defaultDb}.log
printLog $instanceName $defaultDb $res
}
function getAllInstances(){
function getDbs(){
local sql="select datname from pg_database where datname not like 'test%' and datname not like 'backup%' and datname not in ('template0','template1','template2','postgres','template_db','cy7SaasCenter','cy7SaasCenterTest','cy7server','tcposroot','rdsadmin') order by datname;"
local res=$(echo $sql |psql -h $host -p $port -U $user -d $defaultDb -At -v -w)
echo $res
}
function getTime(){
local res=$(date '+%Y%m%d_%H:%M:%S')
echo $res
}
function printLog(){
local res="$(getTime)\t$*"
echo -e $res
echo -e $res >> $log
}
function getDbInfo(){
#echo enter getDbInfo:$1
host=$(jq ".${1}.host" $hosts | sed 's/\"//g')
#echo host:$host
port=$(jq ".${1}.port" $hosts)
user=$(jq ".${1}.user" $hosts | sed 's/\"//g')
pass=$(jq ".${1}.pass" $hosts | sed 's/\"//g')
defaultDb=$(jq ".${1}.defaultdb" $hosts | sed 's/\"//g')
export PGPASSWORD=$pass
#echo getDbInfo:$host,$port,$user,$pass
}
function getSingleDefault(){
instanceName=$1
getDbInfo $instanceName
psql -h $host -p $port -U $user -d $defaultDb -w -f $xjsql > ${xudir}/${instanceName}_${defaultDb}.log
printLog $instanceName $defaultDb $res
}
function getAllDbs(){
instanceName=$1
getDbInfo $instanceName
local dbs=$(getDbs)
for db in $dbs
do
程序的调用部分
需要具体咨询脚本问题的,可以加群。