Skip to content
This repository
branch: master
Phil Dufault November 03, 2013
executable file 157 lines (140 sloc) 5.063 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
#!/usr/bin/env bash
# Phil Dufault (2009)
# bumped to v1 (2011)
# phil@dufault.info

VERSION="1.0.2"
log="$PWD/mysql_error_log.txt"
mysqlCmd="mysql"

echo "MySQL fragmentation finder (and fixer) v$VERSION"
echo "Written by Phil Dufault (phil@dufault.info, http://www.dufault.info)"

showHelp() {
echo -e "\tThis script only repairs MyISAM and InnoDB tables"
echo -e "\t--help -h\t\tthis menu"
echo -e "\t--user username\t\tspecify mysql username to use, the script will prompt for a password during runtime, unless you supply a password"
echo -e "\t--password \"yourpass\""
echo -e "\t--host hostname\t\tspecify mysql hostname to use, be it local (default) or remote"
echo -e "\t--mysql command\t\tspecify mysql command name, default is mysql"
echo -e "\t--database\t\tuse specified database as target\n\t\t\t\tif this option is not used, all databases are targeted"
echo -e "\t--check\t\t\tonly shows fragmented tables, but do not optimize them"
echo -e "\t--detail\t\tadditionally display fragmented tables"
}

# Parse arguments
while [[ $1 == -* ]]; do
case "$1" in
--user) mysqlUser="$2"; shift 2;;
--password) mysqlPass="$2"; shift 2;;
--host) mysqlHost="$2"; shift 2;;
--mysql) mysqlCmd="$2"; shift 2;;
--database) mysqlDb="$2"; shift 2;;
--check) mysqlCheck="1"; shift;;
--detail) mysqlDetail="1"; shift;;
--help|-h) showHelp; exit 0;;
--*) shift; break;;
esac
done

# prevent overwriting the commandline args with the ones in .my.cnf, and check that .my.cnf exists
if [[ ! $mysqlUser && -f "$HOME/.my.cnf" ]]; then
if grep "user=" "$HOME/.my.cnf" >/dev/null 2>&1; then
if grep "password=" "$HOME/.my.cnf" >/dev/null 2>&1; then
mysqlUser=$(grep user= "$HOME/.my.cnf" | awk -F\" '{print $2}');
mysqlPass=$(grep password= "$HOME/.my.cnf" | awk -F\" '{print $2}');
if grep "host=" "$HOME/.my.cnf" >/dev/null 2>&1; then
mysqlHost=$(grep host= "$HOME/.my.cnf" | awk -F\" '{print $2}');
fi
else
echo "Found no pass line in your .my.cnf,, fix this or specify with --password"
fi
else
echo "Found no user line in your .my.cnf, fix this or specify with --user"
exit 1;
fi
fi

# Set localhost if no host is set anywhere else
if [[ ! $mysqlHost ]]; then
mysqlHost="127.0.0.1"
fi

# Error out if no auth details are found for the user
if [[ ! $mysqlUser ]]; then
echo "Authentication information not found as arguments, nor in $HOME/.my.cnf"
echo
showHelp
exit 1
fi

if [[ ! $mysqlPass ]]; then
echo -n "Enter your MySQL password: "
read -s mysqlPass
fi

# Test connecting to the database:
"$mysqlCmd" -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" --skip-column-names --batch -e "show status" >/dev/null 2>"$log"
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information.";
exit 1;
fi

# Retrieve the listing of databases:
if [[ ! $mysqlDb ]]; then
databases=($("$mysqlCmd" -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" --skip-column-names --batch -e "show databases;" 2>"$log"));
else
databases=($mysqlDb);
fi
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information."
exit 1;
fi

echo -e "Found ${#databases[@]} databases";
for i in ${databases[@]}; do
# Get a list of all of the tables, grep for MyISAM or InnoDB, and then sort out the fragmented tables with awk
fragmented=($("$mysqlCmd" -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" --skip-column-names --batch -e "SHOW TABLE STATUS FROM \`$i\`;" 2>"$log" | awk '{print $1,$2,$10}' | egrep "MyISAM|InnoDB|Aria" | awk '$3 > 0' | awk '{print $1}'));
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information."
exit 1;
fi
tput sc

echo -n "Checking $i ... ";
if [[ ${#fragmented[@]} -gt 0 ]]; then
if [[ ${#fragmented[@]} -gt 0 ]]; then
if [[ ${#fragmented[@]} -gt 1 ]]; then
echo "found ${#fragmented[@]} fragmented tables."
else
echo "found ${#fragmented[@]} fragmented table."
fi
if [[ $mysqlDetail ]]; then
for table in ${fragmented[@]}; do
echo -ne "\t$table\n";
done
fi
fi

# Only optimize tables if check option is disabled
if [[ ! $mysqlCheck ]]; then
for table in ${fragmented[@]}; do
let fraggedTables=$fraggedTables+1;
echo -ne "\tOptimizing $table ... ";
"$mysqlCmd" -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" -D "$i" --skip-column-names --batch -e "optimize table \`$table\`" 2>"$log" >/dev/null
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information."
exit 1;
fi
echo done
done
fi
else
tput rc
tput el
fi
unset fragmented
done

# Footer message
if [[ $mysqlCheck ]]; then
echo "Check option was enabled, so no optimizing was done.";
elif [[ ! $fraggedTables -gt 0 ]]; then
echo "No tables were fragmented, so no optimizing was done.";
else
if [[ $fraggedTables -gt 1 ]]; then
echo "$fraggedTables tables were fragmented, and were optimized.";
else
echo "$fraggedTables table was fragmented, and was optimized.";
fi
fi

if [[ ! -s $log ]]; then
rm -f "$log"
fi

unset fraggedTables
Something went wrong with that request. Please try again.