#!/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:-0}" -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) critical_count=$(echo "$critical_count" | tr -d '\n\r' | grep -o '[0-9]*' | head -1) critical_count=${critical_count:-0} print_section "CRITICAL ISSUES: $critical_count found" echo "" if [ "$critical_count" -gt 0 ] 2>/dev/null; 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