A Better Mysqlcheck Script
Mysqlcheck is a stand-alone MySQL utility for checking, optimizing and repairing tables. It’s a useful tool that allows automating the usually time-consuming database maintenance tasks. One of the advantages of mysqlcheck it is ability to run in batch mode and operate on all tables in a database or on multiple databases.
The power of mysqlcheck is not without limitations. One of the tool’s more annoying failings is its inability to recover from connection loss errors. If mysqlcheck is in the process of scanning thousands of tables across multiple databases and the server blinks, mysqlcheck may lose database connection and just quit.
Another limitation of mysqlcheck is its single-threaded nature. On modern multi-core servers with high-performance storage, scanning one table at a time seems an epic waste of time. And in combination with the aforementioned connection loss issue, your entire database maintenance run may cut out early in the run.
Here’s a fairly simple script that will run mysqlcheck on all of your tables in all databases and perform optimization and auto-repair operations. The script will start multiple instances of mysqlcheck, depending on the number of CPU cores on your servers.
#!/bin/bash
# Optimize/repair all tables in all MySQL databases avoiding failure on problem tables
configure() {
# Misc configurable options
db_user=username
db_pass=password
MYSQL="/usr/bin/mysql -A --batch --skip-column-names --max_allowed_packet=100M -h 127.0.0.1 -u${db_user} -p${db_pass}"
cpu_cores=$(fgrep -c processor /proc/cpuinfo)
max_threads=$(echo "scale=0;$${cpu_cores}*4/1"|bc -l)
}
sanity_check() {
# Make sure no other mysqlcheck threads are running
if [ `ps -ef | grep -c "[m]ysqlcheck "` -ne 0 ]
then
echo "An instance of mysqlcheck is already running. Exiting..."
exit 1
fi
}
mysqlcheck_do() {
# Let 'er rip
cd /tmp
$MYSQL -e "show databases" | egrep -v "information_schema|mysql" | while read db_name
do
$MYSQL ${db_name} -e "show tables" | while read table
do
while [ `ps -ef | grep -c "[m]ysqlcheck "` -gt ${max_threads} ]
do
sleep 1
done
echo "Checking ${db_name}.${table}"
nohup mysqlcheck -u${db_user} -p${db_pass} --auto-repair -o ${db_name} ${table} &
done
done
}
# RUNTIME
configure
sanity_check
mysqlcheck_do
