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
| @Service public class MySQLPerformanceDiagnostic { @Autowired private JdbcTemplate jdbcTemplate; @Scheduled(fixedRate = 300000) public void performDiagnostic() { DiagnosticReport report = new DiagnosticReport(); checkSlowQueries(report); checkLockWaits(report); checkIndexUsage(report); checkBufferPoolStatus(report); if (report.hasIssues()) { log.warn("Performance issues detected: {}", report.getSummary()); sendAlert(report); } } private void checkSlowQueries(DiagnosticReport report) { try { List<Map<String, Object>> slowQueries = jdbcTemplate.queryForList( "SELECT SCHEMA_NAME, DIGEST_TEXT, COUNT_STAR, " + "AVG_TIMER_WAIT/1000000000 as avg_time_seconds " + "FROM performance_schema.events_statements_summary_by_digest " + "WHERE AVG_TIMER_WAIT > 1000000000 " + "ORDER BY AVG_TIMER_WAIT DESC LIMIT 10" ); if (!slowQueries.isEmpty()) { report.addIssue("Slow Queries", "Found " + slowQueries.size() + " slow query patterns"); report.addDetail("slowQueries", slowQueries); } } catch (Exception e) { log.error("Error checking slow queries", e); } } private void checkLockWaits(DiagnosticReport report) { try { List<Map<String, Object>> lockWaits = jdbcTemplate.queryForList( "SELECT COUNT(*) as lock_wait_count " + "FROM information_schema.innodb_lock_waits" ); Integer lockWaitCount = (Integer) lockWaits.get(0).get("lock_wait_count"); if (lockWaitCount > 0) { report.addIssue("Lock Waits", "Found " + lockWaitCount + " lock waits"); } } catch (Exception e) { log.error("Error checking lock waits", e); } } private void checkIndexUsage(DiagnosticReport report) { try { List<Map<String, Object>> unusedIndexes = jdbcTemplate.queryForList( "SELECT t.TABLE_SCHEMA, t.TABLE_NAME, t.INDEX_NAME " + "FROM INFORMATION_SCHEMA.STATISTICS t " + "LEFT JOIN performance_schema.table_io_waits_summary_by_index_usage p " + "ON t.TABLE_SCHEMA = p.OBJECT_SCHEMA " + "AND t.TABLE_NAME = p.OBJECT_NAME " + "AND t.INDEX_NAME = p.INDEX_NAME " + "WHERE t.TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys') " + "AND p.INDEX_NAME IS NULL " + "AND t.INDEX_NAME != 'PRIMARY' " + "LIMIT 10" ); if (!unusedIndexes.isEmpty()) { report.addIssue("Unused Indexes", "Found " + unusedIndexes.size() + " potentially unused indexes"); report.addDetail("unusedIndexes", unusedIndexes); } } catch (Exception e) { log.error("Error checking index usage", e); } } private void checkBufferPoolStatus(DiagnosticReport report) { try { Map<String, Object> bufferPoolStats = jdbcTemplate.queryForMap( "SELECT " + "(1 - (Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests)) * 100 as hit_rate " + "FROM (" + "SELECT VARIABLE_VALUE as Innodb_buffer_pool_reads " + "FROM INFORMATION_SCHEMA.GLOBAL_STATUS " + "WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads'" + ") reads, (" + "SELECT VARIABLE_VALUE as Innodb_buffer_pool_read_requests " + "FROM INFORMATION_SCHEMA.GLOBAL_STATUS " + "WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'" + ") requests" ); Double hitRate = (Double) bufferPoolStats.get("hit_rate"); if (hitRate < 95.0) { report.addIssue("Low Buffer Pool Hit Rate", String.format("Buffer pool hit rate is %.2f%%, consider increasing innodb_buffer_pool_size", hitRate)); } } catch (Exception e) { log.error("Error checking buffer pool status", e); } } private void sendAlert(DiagnosticReport report) { log.error("MySQL Performance Alert: {}", report.toJson()); } private static class DiagnosticReport { private List<String> issues = new ArrayList<>(); private Map<String, Object> details = new HashMap<>(); public void addIssue(String category, String description) { issues.add(category + ": " + description); } public void addDetail(String key, Object value) { details.put(key, value); } public boolean hasIssues() { return !issues.isEmpty(); } public String getSummary() { return String.join("; ", issues); } public String toJson() { Map<String, Object> report = new HashMap<>(); report.put("issues", issues); report.put("details", details); report.put("timestamp", System.currentTimeMillis()); try { ObjectMapper mapper = new ObjectMapper(); return mapper.writeValueAsString(report); } catch (Exception e) { return "Error serializing report: " + e.getMessage(); } } } }
|