-
Notifications
You must be signed in to change notification settings - Fork 43
/
mysqlfragfinder.sh
executable file
·180 lines (149 loc) · 5.12 KB
/
mysqlfragfinder.sh
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env bash
# Phil Dufault (2009)
# bumped to v1 (2011)
VERSION="1.0.2"
mysqlCmd="mysql"
echo "MySQL fragmentation finder (and fixer) v$VERSION"
echo "Written by Phil Dufault ([email protected], http://www.dufault.info)"
echo ""
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--log\t\t\tset a custom log. Default value is $PWD/mysqlfragfinder.log"
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;;
--log) log="$2"; shift 2;;
--check) mysqlCheck="1"; shift;;
--detail) mysqlDetail="1"; shift;;
--help|-h) showHelp; exit 0;;
--*) shift; break;;
esac
done
# Set localhost if no host is set anywhere else
if [[ ! $log ]]; then
log="$PWD/mysqlfragfinder.log"
fi
# 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= 'NR==1{print $NF}');
mysqlPass=$(grep "password=" "$HOME/.my.cnf" | awk -F= 'NR==1{print $NF}');
if grep "host=" "$HOME/.my.cnf" >/dev/null 2>&1; then
mysqlHost=$(grep "host=" "$HOME/.my.cnf" | awk -F= 'NR==1{print $NF}');
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
mysqlCmd="$mysqlCmd -u$mysqlUser -p$mysqlPass"
# If set, add -h parameter to mysqlHost
if [[ $mysqlHost ]]; then
mysqlCmd=$mysqlCmd" -h$mysqlHost"
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 --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 --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
if [[ $i != 'information_schema' ]]; then
# Get a list of all of the tables, grep for MyISAM or InnoDB, and then sort out the fragmented tables with awk
fragmented=($($mysqlCmd --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 ""
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 -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
fi
done
echo ""
# 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.";
elif [[ $fraggedTables -gt 1 ]]; then
echo "$fraggedTables tables were fragmented, and were optimized.";
else
echo "$fraggedTables table was fragmented, and was optimized.";
fi
if [[ ! -s $log ]]; then
rm -f "$log"
fi
unset fraggedTables