Files
Linux-Server-Management-Too…/modules/performance/mysql-query-analyzer.sh
T
cschantz a51d968185 Initial commit: Server Management Toolkit v2.0
- Complete security menu restructure (3-mode: Analysis/Actions/Live)
- Intelligent cPHulk enablement with CSF whitelist import
- Live network security monitoring dashboard
- Multi-source threat detection and classification
- 50+ organized security tools across 4-level menu hierarchy
- System health diagnostics with cPanel/WHM integration
- Reference database for cross-module intelligence sharing
2025-11-03 18:21:40 -05:00

423 lines
13 KiB
Bash
Executable File

#!/bin/bash
#############################################################################
# MySQL Query Analyzer
# Deep forensics - identify problematic queries by domain and WordPress plugin
#############################################################################
# Get script directory and load libraries
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"
source "$SCRIPT_DIR/lib/user-manager.sh"
source "$SCRIPT_DIR/lib/mysql-analyzer.sh"
# Require root
require_root
# Create session temp directory
create_temp_session
#############################################################################
# MAIN ANALYSIS
#############################################################################
main() {
clear
print_banner " MySQL Query Analyzer - Deep Forensics"
# Show system info
echo -e "${BOLD}System Detected:${NC}"
echo " Control Panel: $SYS_CONTROL_PANEL"
echo " Database: $SYS_DB_TYPE $SYS_DB_VERSION"
# Count databases and WordPress sites
local total_dbs=$(mysql -Ns -e "SHOW DATABASES" 2>/dev/null | grep -v "^information_schema$\|^mysql$\|^performance_schema$\|^sys$" | wc -l)
local wp_sites=$(find $SYS_USER_HOME_BASE -name "wp-config.php" 2>/dev/null | wc -l)
echo " Databases: $total_dbs total"
echo " WordPress Sites: $wp_sites detected"
echo ""
# Analysis options menu
echo -e "${BOLD}Analysis Options:${NC}"
echo ""
echo -e " ${GREEN}1)${NC} Full System Analysis (all databases)"
echo -e " ${GREEN}2)${NC} Single User Analysis"
echo -e " ${GREEN}3)${NC} Live Query Monitor (real-time)"
echo -e " ${GREEN}4)${NC} Slow Query Log Analysis"
echo -e " ${GREEN}5)${NC} Table Size Analysis"
echo -e " ${GREEN}6)${NC} Quick Health Check"
echo ""
echo -e " ${RED}0)${NC} Back to menu"
echo ""
read -p "Select option: " choice
case $choice in
1) run_full_analysis ;;
2) run_user_analysis ;;
3) run_live_monitor ;;
4) run_slow_query_analysis ;;
5) run_table_size_analysis ;;
6) run_quick_health_check ;;
0) return 0 ;;
*) print_error "Invalid option" ; sleep 2 ; main ;;
esac
}
#############################################################################
# ANALYSIS MODES
#############################################################################
run_full_analysis() {
clear
print_banner "Full System MySQL Analysis"
print_info "This will analyze all databases and queries system-wide..."
echo ""
if ! confirm "Continue with full analysis?"; then
return 0
fi
echo ""
print_section "Phase 1: Capturing Live Queries"
local live_queries=$(capture_live_queries)
print_section "Phase 2: Parsing Slow Query Log"
local slow_queries=$(parse_slow_query_log)
print_section "Phase 3: Analyzing Query Patterns"
local problems=$(analyze_queries_for_problems "$live_queries")
print_section "Phase 4: Analyzing Slow Queries"
analyze_queries_for_problems "$slow_queries" >> "${TEMP_SESSION_DIR}/query_problems.tmp"
print_section "Phase 5: Finding Largest Tables"
local large_tables=$(find_largest_tables 20)
print_section "Phase 6: Generating Statistics"
local stats=$(generate_plugin_statistics "${TEMP_SESSION_DIR}/query_problems.tmp")
echo ""
print_section "Analysis Complete - Generating Report"
echo ""
# Generate comprehensive report
generate_full_report
echo ""
read -p "Press Enter to continue..."
}
run_user_analysis() {
clear
print_banner "Per-User MySQL Analysis"
# Select user
local selected_user=$(select_user_interactive "Select user to analyze")
if [ $? -ne 0 ] || [ -z "$selected_user" ]; then
return 0
fi
if [ "$selected_user" = "ALL" ]; then
run_full_analysis
return 0
fi
echo ""
print_section "Analyzing user: $selected_user"
# Get user databases
local user_dbs=$(get_user_databases "$selected_user")
local db_count=$(echo "$user_dbs" | wc -l)
echo " Databases found: $db_count"
echo "$user_dbs" | sed 's/^/ - /'
echo ""
# Analyze each database
for db in $user_dbs; do
analyze_database "$db" "$selected_user"
done
echo ""
read -p "Press Enter to continue..."
}
run_live_monitor() {
clear
print_banner "Live Query Monitor"
print_info "Monitoring active MySQL queries (press Ctrl+C to stop)"
echo ""
while true; do
clear
print_section "Active Queries - $(date '+%H:%M:%S')"
mysql -e "SHOW FULL PROCESSLIST" 2>/dev/null | while read id user host db command time state info; do
if [ "$command" != "Sleep" ] && [ -n "$info" ] && [ "$info" != "SHOW FULL PROCESSLIST" ]; then
local domain=$(get_database_domain "$db")
local plugin=$(identify_plugin_from_table "$(extract_tables_from_query "$info" | head -1)")
echo -e "${YELLOW}DB: $db${NC} (${CYAN}$domain${NC}) - ${GREEN}$plugin${NC}"
echo " Time: ${time}s"
echo " Query: $(echo "$info" | cut -c1-100)..."
echo ""
fi
done
sleep 2
done
}
run_slow_query_analysis() {
clear
print_banner "Slow Query Log Analysis"
print_info "Analyzing slow query log..."
echo ""
local slow_log=$(parse_slow_query_log)
if [ ! -s "$slow_log" ]; then
print_warning "No slow queries found or slow query log is not enabled"
echo ""
echo "To enable slow query log:"
echo " 1. Edit /etc/my.cnf or /etc/mysql/my.cnf"
echo " 2. Add under [mysqld]:"
echo " slow_query_log = 1"
echo " slow_query_log_file = /var/log/mysql/slow.log"
echo " long_query_time = 2"
echo " 3. Restart MySQL: systemctl restart mysql"
echo ""
read -p "Press Enter to continue..."
return 0
fi
# Analyze slow queries
local problems=$(analyze_queries_for_problems "$slow_log")
# Show top 10 slowest
print_section "Top 10 Problematic Slow Queries"
echo ""
grep "^PROBLEM" "$problems" 2>/dev/null | head -10 | while IFS='|' read -r type domain owner db plugin table issue query_time query; do
echo -e "${RED}[$query_time s] $plugin on $domain${NC}"
echo " Database: $db | Table: $table"
echo " Issue: $issue"
echo " Recommended Fix:"
recommend_fix "$issue" "$db" "$table" "$plugin" | sed 's/^/ /'
echo ""
done
echo ""
read -p "Press Enter to continue..."
}
run_table_size_analysis() {
clear
print_banner "Table Size Analysis"
print_info "Finding largest tables and checking for bloat..."
echo ""
local large_tables=$(find_largest_tables 30)
print_section "Top 30 Largest Tables"
echo ""
printf "${BOLD}%-40s %-30s %15s %10s %20s${NC}\n" "Database" "Table" "Size (MB)" "Bloat" "Plugin"
echo "──────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
while read -r db_name table_name size_mb; do
local plugin=$(identify_plugin_from_table "$table_name")
local domain=$(get_database_domain "$db_name")
local bloat=$(check_table_bloat "$db_name" "$table_name")
local bloat_color="${GREEN}"
[ "$bloat" != "OK" ] && bloat_color="${RED}"
printf "%-40s %-30s %15s ${bloat_color}%10s${NC} %20s\n" \
"$db_name" "$table_name" "${size_mb} MB" "$bloat" "$plugin"
# Recommend optimization if bloated
if [ "$bloat" != "OK" ]; then
echo " → Recommended: OPTIMIZE TABLE \`$db_name\`.\`$table_name\`;"
fi
done < "$large_tables"
echo ""
# Offer to optimize bloated tables
echo ""
if confirm "Optimize bloated tables now? (This may take time)"; then
echo ""
while read -r db_name table_name size_mb; do
local bloat=$(check_table_bloat "$db_name" "$table_name")
if [ "$bloat" != "OK" ]; then
print_info "Optimizing $db_name.$table_name..."
mysql -e "OPTIMIZE TABLE \`$db_name\`.\`$table_name\`" 2>/dev/null
print_success "Optimized $db_name.$table_name"
fi
done < "$large_tables"
fi
echo ""
read -p "Press Enter to continue..."
}
run_quick_health_check() {
clear
print_banner "Quick MySQL Health Check"
echo ""
print_section "Database Server Status"
echo ""
# Check if MySQL is running
if systemctl is-active --quiet mysql 2>/dev/null || systemctl is-active --quiet mariadb 2>/dev/null; then
print_success "MySQL/MariaDB service is running"
else
print_error "MySQL/MariaDB service is NOT running"
fi
# Get current connections
local connections=$(mysql -Ns -e "SHOW STATUS LIKE 'Threads_connected'" | awk '{print $2}')
local max_connections=$(mysql -Ns -e "SHOW VARIABLES LIKE 'max_connections'" | awk '{print $2}')
local conn_percent=$((connections * 100 / max_connections))
echo " Active Connections: $connections / $max_connections (${conn_percent}%)"
if [ $conn_percent -gt 80 ]; then
print_warning "Connection usage is high (${conn_percent}%)"
fi
# Check slow queries
local slow_queries_count=$(mysql -Ns -e "SHOW STATUS LIKE 'Slow_queries'" | awk '{print $2}')
echo " Slow Queries (total): $slow_queries_count"
# Check aborted connections
local aborted=$(mysql -Ns -e "SHOW STATUS LIKE 'Aborted_connects'" | awk '{print $2}')
echo " Aborted Connections: $aborted"
if [ "$aborted" -gt 100 ]; then
print_warning "High number of aborted connections - check for connection issues"
fi
echo ""
print_section "Top 5 Largest Databases"
echo ""
mysql -Ns -e "SELECT table_schema,
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.TABLES
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
GROUP BY table_schema
ORDER BY size_mb DESC
LIMIT 5" 2>/dev/null | while read db size; do
local owner=$(get_database_owner "$db")
local domain=$(get_database_domain "$db")
printf " %-30s %10s MB (%s - %s)\n" "$db" "$size" "$owner" "$domain"
done
echo ""
print_section "Current Resource Usage"
echo ""
echo " CPU Usage: ${CPU_USED}%"
echo " Memory Usage: ${MEM_PERCENT}%"
echo " Load Average: $LOAD_AVERAGE (${LOAD_PERCENT}% of capacity)"
echo ""
read -p "Press Enter to continue..."
}
#############################################################################
# HELPER FUNCTIONS
#############################################################################
analyze_database() {
local db_name="$1"
local username="$2"
print_section "Database: $db_name"
# Get tables
local tables=$(get_database_tables "$db_name")
local table_count=$(echo "$tables" | wc -l)
echo " Tables: $table_count"
# Identify plugins
local plugins=""
for table in $tables; do
local plugin=$(identify_plugin_from_table "$table")
if [ "$plugin" != "WordPress Core" ] && [ "$plugin" != "Unknown Plugin" ]; then
plugins="$plugins\n - $plugin"
fi
done
if [ -n "$plugins" ]; then
echo -e " Plugins detected:$plugins" | sort -u
fi
# Get database size
local db_size=$(mysql -Ns -e "SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2)
FROM information_schema.TABLES
WHERE table_schema='$db_name'" 2>/dev/null)
echo " Size: ${db_size} MB"
echo ""
}
generate_full_report() {
local report_file="/tmp/mysql_analysis_$(date +%Y%m%d_%H%M%S).txt"
local problems_file="${TEMP_SESSION_DIR}/query_problems.tmp"
exec > >(tee "$report_file")
print_banner "MySQL Deep Analysis Report"
echo "Generated: $(date)"
echo "Server: $(hostname)"
echo "Control Panel: $SYS_CONTROL_PANEL"
echo "Database: $SYS_DB_TYPE $SYS_DB_VERSION"
echo ""
# Critical issues
local critical_count=$(grep -c "^PROBLEM" "$problems_file" 2>/dev/null || echo 0)
print_section "CRITICAL ISSUES: $critical_count found"
echo ""
if [ "$critical_count" -gt 0 ]; then
grep "^PROBLEM" "$problems_file" | nl | while read num type domain owner db plugin table issue query_time query; do
echo -e "${RED}[$num] $plugin on $domain${NC}"
echo " Database: $db"
echo " Table: $table"
echo " Issue: $issue"
[ -n "$query_time" ] && [ "$query_time" != "PROBLEM" ] && echo " Query Time: ${query_time}s"
echo " Recommended Fix:"
recommend_fix "$issue" "$db" "$table" "$plugin" | sed 's/^/ /'
echo ""
done
else
print_success "No critical issues detected"
fi
echo ""
print_info "Full report saved to: $report_file"
exec > /dev/tty
}
#############################################################################
# RUN
#############################################################################
main