Saturday, 4 March 2017

Script for MYSQL maintenance (Check,Analyze & Optimize)



Like other relational databases MYSQL do requires scheduled maintenance for optimal performance and catch corruption proactively.As a best practice there should be scheduled maintenance job in place.

Quick benefits of database regular maintenance:
  •  Performance enhancement
  •  Optimal use of hardware resource (return white space to OS by reducing fragmentation,reduce IOPS utilization)
  •  Corruption can be reviewed proactive for databases
  •  Enhance replication sync speed (Master-slave architecture)
  •  Reduce bottleneck of resources (CPU,IO,MEMORY)
Script: I wrote a single generic script which can be use for check, analyze and optimize with few additional parameters which make the script not to write binary logging while maintenance job is running.

How to use: Please refer below the quick snapshot and make use of functions used in script and you can schedule in your cronjob.




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#!/bin/bash

#MYSQL maintenance analyze,optimize and check

#prints usage
usage()
{
    echo version: "$VERSION"
    echo "
Usage: `basename $0` [command] [options]

Commands:
    check                       check all database
    analyze                     analyze all database
    optimize                    optimize all database
    "
}

# creates defaults values
initialize()
{
###############################################
#manual entries by user
    WORKINGDIR=/tmp
    user=root
    pass="google@123"
    VERSION=1.0
#Manual entries section ends
################################################
        CURDATE=`date +%y%m%d_%H%M%S`
#pre-defined defaults, can be overriden
    dLOGDIR=$WORKINGDIR/log
        dCHECKLOG=check_log
        dANALYZELOG=analyze_log
        dOPTIMIZELOG=optimize_log

}
#check if script is already running
if [[ -f /tmp/myscript.running ]] ; then
echo "Script is already running"
#mailx -s "Maintenance script on `hostname` already running"  jasjeet9800@gmail.com
exit
fi
#touch /tmp/myscript.running

if [[ ! -e /tmp/log ]]; then
            mkdir -p /tmp/log
fi

#parses options
parse_options()
{
    if [ -z "$1" ]
    then
        usage
        exit 1
    fi
    case $1 in
    check)                  COMMAND=do_check;;
    analyze)            COMMAND=do_analyze;;
    optimize)           COMMAND=do_optimize;;
    *)                     usage; exit 1;;
    esac
    shift
OPTIONS=$@

    #setting environment variables
        if [ -z $LOGDIR ]
    then
        LOGDIR=$dLOGDIR
    fi
        if [ -z $CHECKLOG ]
    then
        CHECKLOG=${dCHECKLOG}.${CURDATE}
    fi
                if [ -z $ANALYZELOG ]
    then
        ANALYZELOG=${dANALYZELOG}.${CURDATE}
    fi
                if [ -z $OPTIMIZELOG ]
    then
        OPTIMIZELOG=${dOPTIMIZELOG}.${CURDATE}
    fi
    }
#Check All Databases
do_check()
{
touch /tmp/myscript.running
DBNAMES=`mysql -u$user -p$pass -BNse 'show databases'`
for i in $DBNAMES
do

echo "**************************************************************************************** " >>$LOGDIR/$CHECKLOG 2>&1
echo "Checking up $i database (starting time $SECONDS)"        >>$LOGDIR/$CHECKLOG 2>&1
mysqlcheck -u$user -p$pass --check $OPTIONS --skip-write-binlog "$i" >>$LOGDIR/$CHECKLOG 2>&1
echo "Checking on $i database completed (ending time $SECONDS)"  >>$LOGDIR/$CHECKLOG 2>&1
echo "**************************************************************************************** " >>$LOGDIR/$CHECKLOG 2>&1
done
echo $LOGDIR/$CHECKLOG
rm -f /tmp/myscript.running
# mailx -s "MYSQLCHECK for checkdb on `hostname` has been completed" -a "$LOGDIR/$CHECKLOG" jasjeet9800@gmail.com
}

#Analyze all Databases
do_analyze()
{
touch /tmp/myscript.running
DBNAMES=`mysql -u$user -p$pass -BNse 'show databases'`
for i in $DBNAMES
do

echo "**************************************************************************************** " >>$LOGDIR/$ANALYZELOG 2>&1
echo "Analysing up $i database (starting time $SECONDS)"        >>$LOGDIR/$ANALYZELOG 2>&1
mysqlcheck -u$user -p$pass --analyze $OPTIONS --skip-write-binlog "$i" >>$LOGDIR/$ANALYZELOG 2>&1
echo "Analysing on $i database completed (ending time $SECONDS)"  >>$LOGDIR/$ANALYZELOG 2>&1
echo "**************************************************************************************** " >>$LOGDIR/$ANALYZELOG 2>&1
done
echo $LOGDIR/$ANALYZELOG
rm -f /tmp/myscript.running
 #mailx -s "MYSQLCHECK for analyze on `hostname` has been completed" -a "$LOGDIR/$ANALYZELOG" jasjeet9800@gmail.com
}

#Optimize all Databases
do_optimize()
{
touch /tmp/myscript.running
DBNAMES=`mysql -u$user -p$pass -BNse 'show databases'`
for i in $DBNAMES
do

echo "**************************************************************************************** " >>$LOGDIR/$OPTIMIZELOG 2>&1
echo "Checking up $i database (starting time $SECONDS)"        >>$LOGDIR/$OPTIMIZELOG 2>&1
mysqlcheck -u$user -p$pass --optimize $OPTIONS --skip-write-binlog "$i" >>$LOGDIR/$OPTIMIZELOG 2>&1
echo "Checking on $i database completed (ending time $SECONDS)"  >>$LOGDIR/$OPTIMIZELOG 2>&1
echo "**************************************************************************************** " >>$LOGDIR/$CHECKLOG 2>&1
done
echo $LOGDIR/$OPTIMIZELOG
rm -f /tmp/myscript.running
 #mailx -s "MYSQLCHECK for optimize on `hostname` has been completed" -a "$LOGDIR/$OPTIMIZELOG" jasjeet9800@gmail.com

}
initialize
parse_options $@
$COMMAND

exit 0
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Following are quick links as references to study and have understanding on maintenance in deep.

https://dev.mysql.com/doc/refman/5.6/en/optimization.html
https://dev.mysql.com/doc/refman/5.6/en/optimize-table.html
https://dev.mysql.com/doc/refman/5.6/en/mysqlcheck.html
https://dev.mysql.com/doc/refman/5.6/en/myisam-table-maintenance.html
http://www.xaprb.com/blog/2010/02/07/how-often-should-you-use-optimize-table/

Script to monitor MYSQL replication

About Script: 
This shell script can be use as an alternative if there is no monitoring tool in place

Function of script?
It will raise alarm on any of below three conditions comes true
  1. If slave is lagging
  2. If slave is struck
  3. If slave is down 
How to Use?
This script can be scheduled with CRON and will work on polling based mechanism at defined intervals.

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#!/bin/bash
Date=`date`
#DBhost=node1
DBhost=localhost
hostname=`hostname`
DBuser="root"
DBpass="google@123"
MaxDelay="10"

LOG="/tmp/replication_monitor.log"
Slave_OLD_pos=`cat /tmp/.slave_pos`
EMAIL="jasjeet9800@gmail.com"
mysql -u"$DBuser" -p"$DBpass" -h"$DBhost" -e'show slave status \G' > "$LOG"
Slave_NEW_position=`cat "$LOG" |grep "Exec_Master_Log_Pos" |awk '{print $2}'`
slavedelay=`cat "$LOG" |grep "Seconds_Behind_Master"|awk '{print $2}'`

echo "***********************"
echo "Slave old position: "$Slave_OLD_pos
echo "Slave new position: "$Slave_NEW_position
echo "Slave Delay: "$slavedelay"Sec"
echo "***********************"

if [[ $slavedelay -gt $MaxDelay ]]; then
#echo $slavedelay
echo "Slave is behind"
/usr/bin/mail $EMAIL -s "Slave is behind master by $slavedelay on $hostname sec at $Date" <  $LOG
fi

if [[ $slavedelay == "NULL" ]]; then
/usr/bin/mail $EMAIL -s "Slave error occured on $hostname sec at $Date" <  $LOG
echo "Slave error occured"
exit 1
fi

if [[ $Slave_NEW_position -eq $Slave_OLD_pos ]]; then
echo $Slave_NEW_position
/usr/bin/mail $EMAIL -s "Slave is struck on $hostname sec at $Date" <  $LOG
echo "Slave is struck"
fi
echo $Slave_NEW_position > /tmp/.slave_pos
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++