Tuning-primer.sh

From genomewiki
Jump to navigationJump to search

This is a shell script I found on the net. It uses MySQL internals to make recommendations about tuning your MySQL installation by adjusting /etc/my.cnf - the mysql startup file.

Run it at your own risk as root. It worked for me but otherwise comes with no guarantees except the usual one - if it breaks anything of yours, you still own all the pieces.

(Note: The script has been extended. Download from mysqltuner.com, link is on the right-hand side. --Max 18:03, 25 February 2010 (UTC))

#!/usr/bin/env bash

#########################################################################
#                                                                       #
#       MySQL performance tuning primer script                          #
#       Writen by: Matthew Montgomery <mmontgom@rackspace.com>          #
#       Inspired by: MySQLARd (http://gert.sos.be/demo/mysqlar/)        #
#       Version 1.2-r6                                                  #
#       Licenced under GPLv2                                            #
#                                                                       #
#########################################################################
#########################################################################
#                                                                       #
# Set this socket variable if you have multiple instances running or if # 
# we are unable to find your socket otherwise                           #
#                                                                       #
#########################################################################

socket=

function cecho ()

## -- Function to easliy print colored text -- ##

                                # Color-echo.
                                # Argument $1 = message
                                # Argument $2 = color
{
export black='\E[0m\c'
export boldblack='\E[1;0m\c'
export red='\E[31m\c'
export boldred='\E[1;31m\c'
export green='\E[32m\c'
export boldgreen='\E[1;32m\c'
export yellow='\E[33m\c'
export boldyellow='\E[1;33m\c'
export blue='\E[34m\c'
export boldblue='\E[1;34m\c'
export magenta='\E[35m\c'
export boldmagenta='\E[1;35m\c'
export cyan='\E[36m\c'
export boldcyan='\E[1;36m\c'
export white='\E[37m\c'
export boldwhite='\E[1;37m\c'

local default_msg="No message passed."
                                # Doesn't really need to be a local variable.

message=${1:-$default_msg}      # Defaults to default message.
color=${2:-$black}              # Defaults to black, if not specified.

  echo -e "$color"
  echo -e "$message"
  tput sgr0                     # Reset to normal.
  echo -e "$black"
  return
} 

function print_banner () {

## -- Banner -- ##

cecho "\t\c " $black
cecho "-- MYSQL PERFORMANCE TUNING PRIMER --" $boldblue
cecho "\t     - By: Matthew Montgomery -" $black

}

## -- Find the location of the mysql.sock file -- ##

function check_for_socket () {
        if [ -z "$socket" ] ; then
                if [ -S /var/lib/mysql/mysql.sock ] ; then
                        socket=/var/lib/mysql/mysql.sock
                elif [ -S /tmp/mysql.sock ] ; then
                        socket=/tmp/mysql.sock
                else
                        ps_socket=`netstat -ln | egrep "mysql(d)?\.sock" | awk '{ print $9 }'`
                        if [ "$ps_socket" ] ; then
                        socket=$ps_socket
                        fi
                fi
        fi
        if [ -S "$socket" ] ; then
                echo UP > /dev/null
        else
                cecho "No valid socket file "$socket" found!" $boldred
                cecho "mysqld is not running or it is installed in a custom location" $red
                cecho "Please set the $socket variable at the top of this script."
                exit 1
        fi
}


function check_for_plesk_passwords () {

## -- Check for the existance of plesk and login using its credentials -- ##

        if [ -f /etc/psa/.psa.shadow ] ; then
                mysql="mysql -S $socket -u admin -p`cat /etc/psa/.psa.shadow`"
                mysqladmin="mysqladmin -S $socket -u admin -p`cat /etc/psa/.psa.shadow`"
        else
                mysql="mysql -S $socket"
                mysqladmin="mysqladmin -S $socket"
        fi
}

function check_mysql_login () {

## -- Test for running mysql -- ##

        is_up=`$mysqladmin ping 2>&1`
        if [ "$is_up" = "mysqld is alive" ] ; then
                echo UP > /dev/null
        elif [ "$is_up" != "mysqld is alive" ] ; then
                cecho "\n\c"
                cecho "- INITIAL LOGIN ATTEMPT FAILED -\n" $boldred
                if [ -z $prompted ] ; then
                find_webmin_passwords
                else
                        return 1
                fi

        else 
                cecho "Unknow exit status" $red
                exit -1
        fi
}

function final_login_attempt () {
        is_up=`$mysqladmin ping 2>&1`
        if [ "$is_up" = "mysqld is alive" ] ; then
                echo UP > /dev/null
        elif [ "$is_up" != "mysqld is alive" ] ; then
                cecho "- FINAL LOGIN ATTEMPT FAILED -\n" $boldred
                exit 1
        fi
}

function second_login_failed () {

## -- create a ~/.my.cnf and exit when all else fails -- ##

        cecho "- RETRY LOGIN ATTEMPT FAILED -\n" $boldred
        cecho "Could not auto detect login info!\n"
        read -p "Do you have your login handy ? [y/N] : "
        case $REPLY in 
                yes | y | Y | YES)
                answer1='yes'
                read -p "User: " user
                read -rsp "Password: " pass
                export mysql="$mysql -u$user -p$pass"
                export mysqladmin="$mysqladmin -u$user -p$pass"
                ;;
                *)
                cecho "\nPlease create a valid login to MySQL"
                cecho "Or, set correct values for  'user=' and 'password=' in ~/.my.cnf"
                ;;
        esac
        cecho "\n\c"
        read -p "Would you like me to create a ~/.my.cnf file for you? [y/N] : "
        case $REPLY in
                yes | y | Y | YES)
                answer2='yes'
                if [ ! -f ~/.my.cnf ] ; then
                        umask 077
                        echo -e "[client]\nuser=$user\npassword=$pass" > ~/.my.cnf
                        if [ "$answer1" != 'yes' ] ; then
                                exit 1
                        else
                                final_login_attempt
                                return 0
                        fi
                else
                        cecho "\n~/.my.cnf already exists!\n" $boldred
                        read -p "Replace ? [y/N] : "
                        if [ "$REPLY" = 'y' ] || [ "$REPLY = 'Y' " ] ; then 
                        echo -e "[client]\nuser=$user\npassword=$pass" > ~/.my.cnf
                                if [ "$answer1" != 'yes' ] ; then
                                        exit 1
                                else
                                        final_login_attempt
                                        return 0
                                fi
                        else
                                cecho "Please set the 'user=' and 'password=' values in ~/.my.cnf"
                                exit 1
                        fi
                fi
                ;;
                *)
                if [ "$answer1" != 'yes' ] ; then
                        exit 1
                else
                        final_login_attempt
                        return 0
                fi
                ;;
        esac
}

function find_webmin_passwords () {

## -- populate the .my.cnf file using values harvested from Webmin -- ##

        cecho "Testing Stored for passwords:\c"
        if [ -f /etc/webmin/mysql/config ] ; then
                user=`grep ^login= /etc/webmin/mysql/config | cut -d "=" -f 2`
                pass=`grep ^pass= /etc/webmin/mysql/config | cut -d "=" -f 2`
                if [  $user ] && [ $pass ] && [ ! -f ~/.my.cnf  ] ; then
                        cecho "Setting login info as User: $user Password: $pass"
                        touch ~/.my.cnf
                        chmod 600 ~/.my.cnf
                        echo -e "[client]\nuser=$user\npassword=$pass" > ~/.my.cnf 
                        cecho "Retrying login"
                        is_up=`$mysqladmin ping 2>&1`
                        if [ "$is_up" = "mysqld is alive"  ] ; then
                                echo UP > /dev/null
                        else
                                second_login_failed
                        fi
                echo
                else
                        second_login_failed
                echo
                fi
        else
        cecho " None Found\n" $boldred
                second_login_failed
        fi
}

#########################################################################
#                                                                       #
#  Function to pull MySQL status variable                               #
#                                                                       #
#  Call using :                                                         #
#       mysql_status \'Mysql_status_variable\' bash_dest_variable       #
#                                                                       #
#########################################################################

function mysql_status () {
        local status=`$mysql -Bse "show /*!50000 global */ status like $1" | 
                awk '{ print $2 }'`
        export "$2"=$status
}

#########################################################################
#                                                                       #
#  Function to pull MySQL server runtime variable                       #
#                                                                       #
#  Call using :                                                         #
#       mysql_variable \'Mysql_server_variable\' bash_dest_variable     #
#       - OR -                                                          #
#       mysql_variableTSV \'Mysql_server_variable\' bash_dest_variable  #
#                                                                       #
#########################################################################

function mysql_variable () {
        local variable=`$mysql -e "show /*!500000 global */ variables like $1" | 
                grep -v Variable_name | awk '{ print $2 }'`
        export "$2"=$variable
}
function mysql_variableTSV () {
        local variable=`$mysql -e "show variables like $1" | 
                grep -v Variable_name | awk -F \t '{ print $2 }'`
        export "$2"=$variable
}

function divide () {

# -- Divide two intigers -- #

        usage="$0 dividend divisor '$variable' scale"
        if [ $1 -ge 1 ] ; then
                dividend=$1
        else
                cecho "Invalid Dividend" $red
                echo $usage
                exit 1
        fi
        if [ $2 -ge 1 ] ; then
                divisor=$2
        else
                cecho "Invalid Divisor" $red
                echo $usage
                exit 1
        fi
        if [ ! -n $3 ] ; then
                cecho "Invalid variable name" $red
                echo $usage
                exit 1
        fi
        if [ -z $4 ] ; then
                scale=2
        elif [ $4 -ge 0 ] ; then
                scale=$4
        else
                cecho "Invalid scale" $red
                echo $usage
                exit 1
        fi
        export $3=$(echo "scale=$scale; $dividend / $divisor" | bc -l)
}

function human_readable () {

#########################################################################
#                                                                       #
#  Convert a value in to human readable size and populate a variable    #
#  with the result.                                                     #
#                                                                       #
#  Call using:                                                          #
#       human_readable $value 'variable name'                           #
#                                                                       #
#########################################################################

        ## value=$1
        ## variable=$2
        scale=$3

        if [ $1 -gt 1048576 ] ; then
                if [ -z $3 ] ; then 
                        scale=0
                fi
                divide $1 1048576 "$2" $scale
                unit="M"
        elif [ $1 -gt 1024 ] ; then
                if [ -z $3 ] ; then
                        scale=2
                fi
                divide $1 1024 "$2" $scale
                unit="K"
        else
                export "$2"=$1
                unit="bytes"
        fi
        # let "$2"=$HR
}

function human_readable_time () {

########################################################################
#                                                                      #
#       Function to produce human readable time                        #
#                                                                      #
########################################################################

        usage="$0 seconds 'variable'"
        if [ -z $1 ] || [ -z $2 ] ; then
                cecho $usage $red
                exit 1
        fi
        days=$(echo "scale=0 ; $1 / 86400" | bc -l)
        remainder=$(echo "scale=0 ; $1 % 86400" | bc -l)
        hours=$(echo "scale=0 ; $remainder / 3600" | bc -l)
        remainder=$(echo "scale=0 ; $remainder % 3600" | bc -l)
        minutes=$(echo "scale=0 ; $remainder / 60" | bc -l)
        seconds=$(echo "scale=0 ; $remainder % 60" | bc -l)
        export $2="$days days $hours hrs $minutes min $seconds sec"
}

function check_mysql_version () {

## -- Print Version Info -- ##

        mysql_variable \'version\' mysql_version
        mysql_variable \'version_compile_machine\' mysql_version_compile_machine

        cecho "MySQL Version $mysql_version $mysql_version_compile_machine"
}

function post_uptime_warning () {

#########################################################################
#                                                                       #
#  Present a reminder that mysql must run for a couple of days to       #
#  build up good numbers in server status variables before these tuning #
#  suggestions should be used.                                          #
#                                                                       #
#########################################################################

        mysql_status \'Uptime\' uptime
        mysql_status \'Threads_connected\' threads
        let queries_per_sec=$questions/$uptime
        human_readable_time $uptime uptimeHR

        cecho "Uptime = $uptimeHR"
        cecho "Avg. qps = $queries_per_sec"
        cecho "Total Questions = $questions"
        cecho "Threads Connected = $threads"
        echo

        if [ $uptime -gt 172800 ] ; then
                cecho "Server has been running for over 48hrs."
                cecho "It should be safe to follow these recommendations"
        else
                cecho "Warning: \c" $boldred
                cecho "Server has not been running for at least 48hrs." $boldred
                cecho "It may not be safe to use these recommendations" $boldred

        fi
        echo ""
        cecho "To find out more information on how each of these" $red
        cecho "runtime variables effects performance visit:" $red
        if [ $major_version == '3.23' ] || [ $major_version == '4.0' ] || [ $major_version == '4.1' ]; then
        cecho "http://dev.mysql.com/doc/refman/4.1/en/server-system-variables.html" $boldblue
        elif [ $major_version == '5.0' ] || [ $major_version == '5.1' ] ; then
        cecho "http://dev.mysql.com/doc/refman/$major_version/en/server-system-variables.html" $boldblue
        else
        echo "UNSUPPORTED MYSQL VERSION"
        exit 1
        fi
}

function check_slow_queries () {

## -- Slow Queries -- ## 

        cecho "SLOW QUERIES" $boldblue

        mysql_status \'Slow_queries\' slow_queries
        mysql_variable \'long_query_time\' long_query_time
        mysql_variable \'log%queries\' log_slow_queries
        prefered_query_time=5
        if [ -e /etc/my.cnf ] ; then
                if [ -z $log_slow_queries ] ; then
                        log_slow_queries=`grep log-slow-queries /etc/my.cnf`
                fi
        fi
        cecho "Current long_query_time = $long_query_time sec."
        cecho "You have \c"
        cecho "$slow_queries \c" $boldred 
        cecho "out of \c"
        cecho "$questions \c" $boldred
        cecho "that take longer than $long_query_time sec. to complete"

        if [ "$log_slow_queries" = 'ON' ] ; then
                cecho "The slow query log is enabled."
        elif [ "$log_slow_queries" = 'OFF' ] ; then
                cecho "The slow query log is \c"
                cecho "NOT \c" $boldred
                cecho "enabled."
        elif [ -z $log_slow_queries ] ; then
                cecho "The slow query log is \c"
                cecho "NOT \c" $boldred
                cecho "enabled."
        else
                cecho "Error: $log_slow_queries" $boldred
        fi

        if [ $long_query_time -gt $prefered_query_time ] ; then
                cecho "Your long_query_time may be too high, I typically set this under $prefered_query_time sec." $red
        else
                cecho "Your long_query_time seems to be fine" $green
        fi 
}

function check_used_connections () {

## -- Used Connections -- ##

        mysql_variable \'max_connections\' max_connections
        mysql_status \'Max_used_connections\' max_used_connections
        mysql_status \'Threads_connected\' threads_connected

        let connections_ratio=$max_used_connections*100/$max_connections

        cecho "MAX CONNECTIONS" $boldblue
        cecho "Current max_connections = $max_connections"
        cecho "Current threads_connected = $threads_connected"
        cecho "Historic max_used_connections = $max_used_connections"
        cecho "The number of used connections is \c"
        if [ $connections_ratio -ge 85 ] ; then
                txt_color=$red
        else 
                txt_color=$green
        fi
        # cecho "$max_used_connections \c" $txt_color
        # cecho "which is \c"
        cecho "$connections_ratio% \c" $txt_color
        cecho "of the configured maximum."
        unset txt_color

        if [ $connections_ratio -ge 85 ] ; then
                cecho "You should raise max_connections" $red
        else 
                cecho "Your max_connections variable seems to be fine." $green
        fi
}

function check_threads() {

## -- Worker Threads -- ##

        cecho "WORKER THREADS" $boldblue

        mysql_status \'Threads_created\' threads_created1
        sleep 1
        mysql_status \'Threads_created\' threads_created2

        mysql_status \'Threads_cached\' threads_cached
        mysql_status \'Uptime\' uptime
        mysql_variable \'thread_cache_size\' thread_cache_size

        let historic_threads_per_sec=$threads_created1/$uptime
        let current_threads_per_sec=$threads_created2-$threads_created1;

        cecho "Current thread_cache_size = $thread_cache_size"
        cecho "Current threads_cached = $threads_cached"
        cecho "Current threads_per_sec = $current_threads_per_sec"
        cecho "Historic threads_per_sec = $historic_threads_per_sec"

        if [ $historic_threads_per_sec -ge 2 ] && [ $threads_cached -le 1 ] ; then
                cecho "Threads created per/sec are overrunning threads cached" $red
                cecho "You should raise thread_cache_size" $red
        elif [ $current_threads_per_sec -ge 2 ] ; then
                cecho "Threads created per/sec are overrunning threads cached" $red
                cecho "You should raise thread_cache_size" $red
        else
                cecho "Your thread_cache_size is fine" $green
        fi
}

function check_key_buffer_size () {

## -- Key buffer Size -- ##

        cecho "KEY BUFFER" $boldblue

        mysql_status \'Key_read_requests\' key_read_requests
        mysql_status \'Key_reads\' key_reads
        mysql_status \'Key_blocks_used\' key_blocks_used
        mysql_status \'Key_blocks_unused\' key_blocks_unused
        mysql_variable \'key_buffer_size\' key_buffer_size
        mysql_variable \'datadir\' datadir

        
        myisam_indexes=`$mysql -Bse "/*!50000 SELECT SUM(INDEX_LENGTH) from information_schema.TABLES where ENGINE='MyISAM' 
*/"`
        OS=$(uname)

        if [ "$OS" == 'Darwin' ] || [ "$OS" == 'FreeBSD' ] || [ "$OS" == 'OpenBSD' ] ; then
                duflags=
        else
                duflags='-b'
        fi
        if [ -z "$myisam_indexes" ] ; then
                myisam_indexes=`find $datadir -name '*.MYI' -exec du $duflags '{}' \; | awk '{ s += $1 } END { 
printf("%i\n", s )}'`
        fi

        if [ $key_reads -eq 0 ] ; then
                cecho "No key reads?!" $boldred
                cecho "Seriously look into using some indexes" $red
                key_cache_miss_rate=0
                key_buffer_ratio=0
                key_buffer_ratioRND=0
        else
                let key_cache_miss_rate=$key_read_requests/$key_reads
                if [ ! -z $key_blocks_unused ] ; then
                        let key_blocks_total=$key_blocks_used+$key_blocks_unused
                        divide $key_blocks_used $key_blocks_total key_buffer_fill 2
                        key_buffer_ratio=$(echo "$key_buffer_fill * 100" | bc -l)
                        key_buffer_ratioRND=$(echo "scale=0; $key_buffer_ratio / 1" | bc -l)
                else
                        key_buffer_ratio='Unknown'
                        key_buffer_ratioRND=75
                fi
        fi

        human_readable $myisam_indexes myisam_indexes_HR 0
        cecho "Current MyISAM index space = $myisam_indexes_HR $unit" 

        human_readable  $key_buffer_size key_buffer_size_HR 0
        cecho "Current key_buffer_size = $key_buffer_size_HR $unit"
        cecho "Key cache miss rate is 1 / $key_cache_miss_rate"
        cecho "Key buffer fill ratio = $key_buffer_ratio %" 

        if [ $key_cache_miss_rate -le 100 ] && [ $key_cache_miss_rate -gt 0 ] && [ $key_buffer_ratioRND -ge 80 ]; then
                cecho "You could increase key_buffer_size" $boldred
                cecho "It is safe to raise this up to 1/4 of total system memory;"
                cecho "assuming this is a dedicated database server."
        elif [ $key_buffer_ratioRND -ge 80 ] && [ $key_buffer_size -le $myisam_indexes ] ; then
                cecho "You could increase key_buffer_size" $boldred
                cecho "It is safe to raise this up to 1/4 of total system memory;"
                cecho "assuming this is a dedicated database server."
        elif [ $key_cache_miss_rate -ge 10000 ] || [ $key_buffer_ratioRND -le 50  ] ; then
                cecho "Your key_buffer_size seems to be too high." $red 
                cecho "Perhaps you can use these resources elsewhere" $red
        else
                cecho "Your key_buffer_size seems to be fine" $green
        fi
}

function check_query_cache () {

## -- Query Cache -- ##

        cecho "QUERY CACHE" $boldblue

        mysql_variable \'version\' mysql_version
        mysql_variable \'query_cache_size\' query_cache_size
        mysql_status \'Qcache_free_memory\' qcache_free_memory
        mysql_status \'Qcache_lowmem_prunes\' qcache_lowmem_prunes

        if [ -z $query_cache_size ] ; then
                cecho "You are using MySQL $mysql_version, no query cache is supported. \nI recommend an upgrade to MySQL 
4.0 or better" $red
        elif [ $query_cache_size -eq 0 ] ; then
                cecho "Query cache is supported but not enabled" $red
                cecho "Perhaps you should set the query_cache_size" $red
        else
                let qcache_used_memory=$query_cache_size-$qcache_free_memory
                qcache_fill_ratio=$(echo "scale=2; $qcache_used_memory * 100 / $query_cache_size" | bc -l)
                qcache_fill_ratio_HR=$(echo "scale=0; $qcache_fill_ratio / 1" | bc -l)
                cecho "Query cache is enabled" $green
                human_readable $query_cache_size query_cache_size_HR
                cecho "Current query_cache_size = $query_cache_size_HR $unit"
                human_readable $qcache_used_memory qcache_used_memory_HR
                cecho "Current query_cache_used = $qcache_used_memory_HR $unit"
                cecho "Current Query cache fill ratio = $qcache_fill_ratio %"
                if [ $qcache_fill_ratio_HR -le 25 ] ; then
                        cecho "Your query_cache_size seems to be too high." $red
                        cecho "Perhaps you can use these resources elsewhere" $red
                fi
                if [ $qcache_lowmem_prunes -ge 50 ] && [ $qcache_fill_ratio_HR -ge 80 ]; then
                        cecho "However, \c"
                        cecho "$qcache_lowmem_prunes \c" $boldred
                        cecho "queries have been removed from the query cache due to lack of memory"
                        cecho "Perhaps you should raise query_cache_size" $boldred
                fi
        fi

}

function check_sort_operations () {

## -- Sort Operations -- ##

        cecho "SORT OPERATIONS" $boldblue

        mysql_status \'Sort_merge_passes\' sort_merge_passes
        mysql_status \'Sort_scan\' sort_scan
        mysql_status \'Sort_range\' sort_range
        mysql_variable \'sort_buffer%\' sort_buffer_size 
        mysql_variable \'read_rnd_buffer_size\' read_rnd_buffer_size 

        let total_sorts=$sort_scan+$sort_range
        if [ -z $read_rnd_buffer_size ] ; then
                mysql_variable \'record_buffer\' read_rnd_buffer_size
        fi

        ## Correct rounding error in mysqld where 512K != 524288 ##
        let sort_buffer_size=$sort_buffer_size+8
        let read_rnd_buffer_size=$read_rnd_buffer_size+8

        human_readable $sort_buffer_size sort_buffer_size_HR
        cecho "Current sort_buffer_size = $sort_buffer_size_HR $unit"

        human_readable $read_rnd_buffer_size read_rnd_buffer_size_HR
        cecho "Current record/read_rnd_buffer_size = $read_rnd_buffer_size_HR $unit"

        if [ $total_sorts -eq 0 ] ; then 
                cecho "No sort operations have been performed"
                passes_per_sort=0
        fi
        if [ $sort_merge_passes -ne 0 ] ; then
                let passes_per_sort=$sort_merge_passes/$total_sorts
        else
                passes_per_sort=0
        fi

        if [ $passes_per_sort -ge 2 ] ; then
                cecho "On average \c"
                cecho "$passes_per_sort \c" $boldred
                cecho "sort merge passes are made per sort operation"
                cecho "You should raise your sort_buffer_size"
                cecho "You should also raise your \c"
                if [ $major_version == '3.23' ] ; then 
                        cecho "record_rnd_buffer_size"
                else
                        cecho "read_rnd_buffer_size"
                fi
        else
                cecho "Sort buffer seems to be fine" $green
        fi
}

function check_join_operations () {

## -- Joins -- ##

        cecho "JOINS" $boldblue

        mysql_status \'Select_full_join\' select_full_join
        mysql_status \'Select_range_check\' select_range_check
        mysql_variable \'join_buffer%\' join_buffer_size

        human_readable $join_buffer_size join_buffer_size_HR

        cecho "Current join_buffer_size = $join_buffer_size_HR $unit"
        cecho "You have had $select_full_join queries where a join could not use an index properly"

        if [ $select_range_check -eq 0 ] && [ $select_full_join -eq 0 ] ; then
                cecho "Your joins seem to be using indexes properly" $green
        fi
        if [ $select_full_join -gt 0 ] ; then
                print_error='true'
        fi
        if [ $select_range_check -gt 0 ] ; then
                cecho "You have had $select_range_check joins without keys that check for key usage after each row" $red
                print_error='true'
        fi
        ## Debuging ##
        # print_error='true'
        if [ $print_error ] ; then 
                if [ $major_version == '3.23' ] || [ $major_version == '4.0' ] ; then
                        cecho "You should enable \"log-long-format\" "
                elif [ $major_version == '4.1' ] || [ $major_version == '5.0' ] || [ $major_version == '5.1' ] ; then
                        cecho "You should enable \"log-queries-not-using-indexes\""
                fi
                cecho "Then look for non indexed joins in the slow query log."
                cecho "If you are unable to optimize your queries you may want to increase your"
                cecho "join_buffer_size to accommodate larger joins in one pass."
        fi

        # XXX Add test for join_buffer_size 
}

check_tmp_tables () {

## -- Temp Tables -- ##

        cecho "TEMP TABLES" $boldblue

        mysql_status \'Created_tmp_tables\' created_tmp_tables 
        mysql_status \'Created_tmp_disk_tables\' created_tmp_disk_tables
        mysql_variable \'tmp_table_size\' tmp_table_size

        human_readable $tmp_table_size tmp_table_size_HR 

        if [ $created_tmp_tables -eq 0 ] ; then
                tmp_disk_tables=0
        else
                let tmp_disk_tables=created_tmp_disk_tables*100/created_tmp_tables
        fi
        cecho "Current tmp_table_size = $tmp_table_size_HR $unit"
        cecho "$tmp_disk_tables% of tmp tables created were disk based"
        if [ $tmp_disk_tables -ge 25 ] ; then
                cecho "Perhaps you should increase your tmp_table_size" $red
        else
                cecho "Created disk tmp tables ratio seems fine" $green
        fi
}

function check_table_cache () {

## -- Table Cache -- ##

        cecho "TABLE CACHE" $boldblue

        mysql_variable \'datadir\' datadir
        mysql_variable \'table_cache\' table_cache

        ## /* MySQL +5.1 version of table_cache */ ## 
        mysql_variable \'table_open_cache\' table_open_cache
        mysql_variable \'table_definition_cache\' table_definition_cache

        mysql_status \'Open_tables\' open_tables
        mysql_status \'Opened_tables\' opened_tables
        mysql_status \'Open_table_definitions\' open_table_definitions
 
#       socket_owner=`find $socket -printf '%u\n'`
        socket_owner=`ls -l $socket | awk '{ print $3 }'`
        script_runner=`whoami`

        table_count=`$mysql -Bse "/*!50000 SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE' 
*/"`

        if [ -z $table_count ] ; then
                if [ "$script_runner" != "$socket_owner" ] && [ "$script_runner" != "root" ] ; then
                        cecho "You are not '$socket_owner' or 'root'" $red
                        cecho "I am unable to determine the table_count!" $red
                else
                        table_count=`find $datadir 2>&1 | grep -c .frm$`
                fi
        fi
        if [ $table_open_cache ] ; then
                table_cache=$table_open_cache
        fi

        if [ $opened_tables -ne 0 ] && [ $table_cache -ne 0 ] ; then 
                let table_cache_hit_rate=$open_tables*100/$opened_tables
                let table_cache_fill=$open_tables*100/$table_cache
        elif [ $opened_tables -eq 0 ] && [ $table_cache -ne 0 ] ; then
                table_cache_hit_rate=100
                let table_cache_fill=$open_tables*100/$table_cache
        else
                cecho "ERROR no table_cache ?!" $boldred
                exit 1
        fi
        if [ $table_cache ] && [ ! $table_open_cache ] ; then
                cecho "Current table_cache value = $table_cache tables"
        fi
        if [ $table_open_cache ] ; then
                cecho "Current table_open_cache = $table_open_cache tables"
                cecho "Current table_definition_cache = $table_definition_cache tables"
        fi
        if [ $table_count ] ; then
        cecho "You have a total of $table_count tables"
        fi

        if  [ $table_cache_fill -lt 95 ] ; then
                cecho "You have \c"
                cecho "$open_tables \c" $green
                cecho "open tables." 
                cecho "The table_cache value seems to be fine" $green
        elif [ $table_cache_hit_rate -le 85 -o  $table_cache_fill -ge 95 ]; then
                cecho "You have \c"
                cecho "$open_tables \c" $boldred
                cecho "open tables."
                cecho "Current table_cache hit rate is \c" 
                cecho "$table_cache_hit_rate%\c" $boldred
                cecho ", while \c"
                cecho "$table_cache_fill% \c" $boldred
                cecho "of your table cache is in use"
                cecho "You should probably increase your table_cache" $red
        else
                cecho "Current table_cache hit rate is \c"
                cecho "$table_cache_hit_rate%\c" $green
                cecho ", while \c"
                cecho "$table_cache_fill% \c" $green
                cecho "of your table cache is in use"
                cecho "The table cache value seems to be fine" $green
        fi
        if [ $table_definition_cache ] && [ $table_definition_cache -le $table_count ] && [ $table_count -ge 100 ] ; then
                cecho "You should probably increase your table_definition_cache value." $red
        fi
}

function check_table_locking () {

## -- Table Locking -- ##

        cecho "TABLE LOCKING" $boldblue

        mysql_status \'Table_locks_waited\' table_locks_waited
        mysql_status \'Table_locks_immediate\' table_locks_immediate
        mysql_variable \'concurrent_insert\' concurrent_insert
        mysql_variable \'low_priority_updates\' low_priority_updates
        if [ "$concurrent_insert" = 'ON' ]; then
                let concurrent_insert=1
        elif [ "$concurrent_insert" = 'OFF' ]; then
                let concurrent_insert=0
        fi

        cecho "Current Lock Wait ratio = \c"
        if [ $table_locks_waited -gt 0 ]; then
                let immediate_locks_miss_rate=$table_locks_immediate/$table_locks_waited
                cecho "1 : $immediate_locks_miss_rate" $red 
        else
                let immediate_locks_miss_rate=99999 # perfect
                cecho "0 : $questions" $green
        fi
        if [ $immediate_locks_miss_rate -lt 5000 ] ; then
                cecho "You may benefit from selective use of InnoDB."
                if [ "$low_priority_updates" == 'OFF' ] ; then
                cecho "If you have long running SELECT's against MyISAM tables \c"
                cecho "and perform frequent updates consider setting 'low_priority_updates=1'"
                fi
                if [ $concurrent_insert -le 1 ] && [ $major_version == '5.0' ] ; then
                cecho "If you have a high concurrentcy of inserts on Dynamic row-lenght tables \c"
                cecho "consider setting 'concurrent_insert=2'."
                elif  [ $concurrent_insert -le 1 ] && [ $major_version == '5.1' ] ; then
                cecho "If you have a high concurrentcy of inserts on Dynamic row-lenght tables \c"
                cecho "consider setting 'concurrent_insert=2'."
                fi
        else
                cecho "Your table locking seems to be fine" $green
        fi
}

function check_table_scans () {

## -- Table Scans -- ##

        cecho "TABLE SCANS" $boldblue

        mysql_status \'Com_select\' com_select
        mysql_status \'Handler_read_rnd_next\' read_rnd_next
        mysql_variable \'read_buffer_size\' read_buffer_size

        if [ -z $read_buffer_size ] ; then
                mysql_variable \'record_buffer\' read_buffer_size
        fi

        human_readable $read_buffer_size read_buffer_size_HR
        cecho "Current read_buffer_size = $read_buffer_size_HR $unit"

        if [ $com_select -gt 0 ] ; then
                let full_table_scans=$read_rnd_next/$com_select 
                cecho "Current table scan ratio = $full_table_scans : 1"
                if [ $full_table_scans -ge 4000 ] && [ $read_buffer_size -le 2097152 ] ; then
                        cecho "You have a high ratio of sequential access requests to SELECTs" $red
                        cecho "You may benefit from raising \c" $red
                        if [ $major_version == '3.23' ] ; then 
                                cecho "record_buffer \c" $red
                        else
                                cecho "read_buffer_size \c" $red
                        fi
                        cecho "and/or improving your use of indexes." $red
                elif [ $read_buffer_size -gt 2097152 ] ; then 
                        cecho "read_buffer_size is over 2 MB \c" $red 
                        cecho "there is probably no need for such a large read_buffer" $red

                else
                        cecho "read_buffer_size seems to be fine" $green
                fi
        else
                cecho "read_buffer_size seems to be fine" $green
        fi
}


function check_innodb_status () {

## -- InnoDB -- ##

        mysql_variable \'have_innodb\' have_innodb

        if [ "$have_innodb" = "YES" ] ; then
                mysql_variable \'innodb_buffer_pool_size\' innodb_buffer_pool_size
                echo
                cecho "INNODB STATUS" $boldblue
                innodb_indexes=`$mysql -Bse "/*!50000 SELECT SUM(INDEX_LENGTH) from information_schema.TABLES where 
ENGINE='InnoDB' */"`

                if [ ! -z "$innodb_indexes" ] ; then
                human_readable $innodb_indexes innodb_indexes_HR 0
                cecho "Current InnoDB index space = $innodb_indexes_HR $unit"
                else
                cecho "Cannot find InnoDB index space prior to 5.0.x" $red
                fi

                human_readable $innodb_buffer_pool_size innodb_buffer_pool_sizeHR
                cecho "Current innodb_buffer_pool_size = $innodb_buffer_pool_sizeHR $unit"
                cecho "Depending on how much space your innodb indexes take up it may be safe"  
                cecho "to increase this value to up to 1 / 3 of total system memory"
                echo
                $mysql -s -e "SHOW /*!50000 ENGINE */INNODB STATUS\G"
        else
                cecho "No InnoDB Support Enabled!" $boldred
        fi
}

function total_memory_used () {

## -- Total Memory Usage -- ##
        cecho "MEMORY USAGE" $boldblue

        mysql_variable \'read_buffer_size\' read_buffer_size
        mysql_variable \'sort_buffer_size\' sort_buffer_size
        mysql_variable \'thread_stack\' thread_stack
        mysql_variable \'max_connections\' max_connections
        mysql_status \'Max_used_connections\' max_used_connections

        let per_thread_buffers=($read_buffer_size+$sort_buffer_size+$thread_stack)*$max_used_connections
        let per_thread_max_buffers=($read_buffer_size+$sort_buffer_size+$thread_stack)*$max_connections

        mysql_variable \'innodb_buffer_pool_size\' innodb_buffer_pool_size
        if [ -z $innodb_buffer_pool_size ] ; then
        innodb_buffer_pool_size=0
        fi

        mysql_variable \'innodb_additional_mem_pool_size\' innodb_additional_mem_pool_size
        if [ -z $innodb_additional_mem_pool_size ] ; then
        innodb_additional_mem_pool_size=0
        fi

        mysql_variable \'innodb_log_buffer_size\' innodb_log_buffer_size
        if [ -z $innodb_log_buffer_size ] ; then
        innodb_log_buffer_size=0
        fi

        mysql_variable \'key_buffer_size\' key_buffer_size

        mysql_variable \'query_cache_size\' query_cache_size
        if [ -z $query_cache_size ] ; then
        query_cache_size=0
        fi


        let 
global_buffers=$innodb_buffer_pool_size+$innodb_additional_mem_pool_size+$innodb_log_buffer_size+$key_buffer_size+$query_cache_size

        let total_memory=$global_buffers+$per_thread_buffers
        let max_memory=$global_buffers+$per_thread_max_buffers
        human_readable $total_memory total_memoryHR 0
        cecho "Max Memory Ever Allocated : $total_memoryHR $unit" $boldred
        human_readable $max_memory max_memoryHR 0
        cecho "Configured Max Memory Limit : $max_memoryHR $unit" $boldred

        total_system_memory=`free -b | grep -v buffers |  awk '{ s += $2 } END { printf("%ld\n", s ) }'`
        human_readable $total_system_memory total_system_memoryHR 0
        cecho "Total System Memory : $total_system_memoryHR $unit" $boldred
}

function snarky () {

## -- Be Snarky -- ##

        fortune=`which fortune 2>/dev/null` 
        if [ -z $fortune ] ; then
                echo "What the hell sort of straight-lace bastard doesn't have fortune installed?"
        else
                $fortune
        fi
}

## Required Functions  ## 

function login_validation () {
        check_for_socket                # determine the socket location -- 1st login
        check_for_plesk_passwords       # determine the login method -- 2nd login
        check_mysql_login               # determine if mysql is accepting login -- 3rd login
        export major_version=`$mysql -Bse 'select substring_index(version(), ".", +2)'`
        export OS=`uname`
        mysql_status \'Questions\' questions
}

## Optional Components Groups ##

function banner_info () {
        print_banner            ; echo
        check_mysql_version     ; echo
        post_uptime_warning     ; echo
}

function misc () {
        check_slow_queries      ; echo
        check_used_connections  ; echo
        check_threads           ; echo
}

function memory () {
        total_memory_used       ; echo
        check_key_buffer_size   ; echo
        check_query_cache       ; echo
        check_sort_operations   ; echo
        check_join_operations   ; echo
}

function file () {
        check_table_cache       ; echo
        check_tmp_tables        ; echo
        check_table_scans       ; echo
        check_table_locking     ; echo
}

function all () {
        banner_info
        misc
        memory
        file
#       snarky
}

function prompt () {
        prompted='true'
        read -p "Username [anonymous] : " user
        read -rsp "Password [<none>] : " pass
        cecho "\n\c"
        read -p "Socket [ /var/lib/mysql/mysql.sock ] : " socket
        if [ -z $socket ] ; then
                export socket='/var/lib/mysql/mysql.sock'
        fi
        if [ -n $pass ] ; then
                pass_flag='-p'
        fi
        mysql="mysql -S $socket -u$user $pass_flag$pass"
        mysqladmin="mysqladmin -S $socket -u$user $pass_flag$pass"
        echo $mysql
        check_for_socket
        check_mysql_login
        if [ $? = 1 ] ; then
                exit 1
        fi
        read -p "Mode to test (see usage:) [all] : " pmode
        case $pmode in
                banner )
                banner_info 
                ;;
                misc )
                misc
                ;;
                memory )
                memory
                ;; 
                file )
                file
                ;;
                innodb )
                innodb
                ;;
                all | *)
                all
                ;;
        esac 
}

if [ -z $1 ] ; then
        login_validation
        mode='ALL'
elif [ "$1" != "prompt" ] || [ "$1" != "PROMPT" ] ; then
        login_validation
        mode=$1
elif [ "$1" = "prompt" ] || [ "$1" = "PROMPT" ] ; then
        mode=$1
fi

case $mode in 
        ALL | all )
        cecho "\n\c"
        all
        ;;
        mem | memory |  MEM | MEMORY )
        cecho "\n\c"
        memory
        ;;
        file | FILE | disk | DISK )
        cecho "\n\c"
        file
        ;;
        banner | BANNER | header | HEADER | head)
        banner_info
        ;;
        misc | MISC | miscelaneous )
        cecho "\n\c"
        misc
        ;;
        innodb | INNODB )
        banner_info
        check_innodb_status ; echo
        ;;
        prompt | PROMPT )
        prompt
        ;;
        *)
        cecho "usage: $0 [ all | banner | file | innodb | memory | misc | promp ]" $boldred
        exit 1
        ;;
esac