added typeaheead and introspetion
This commit is contained in:
@@ -2851,6 +2851,70 @@ struct WorkbenchAdministrationView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 69: advisory diagnostics from the already loaded server snapshot.
|
||||
// No additional queries, writes, or persistent SQL text are required.
|
||||
private var diagnosticFindings: [String] {
|
||||
func cell(_ row: [String], _ name: String) -> String {
|
||||
guard let index = result.columns.firstIndex(where: { $0.caseInsensitiveCompare(name) == .orderedSame }),
|
||||
index < row.count else { return "" }
|
||||
return row[index]
|
||||
}
|
||||
func number(_ row: [String], _ name: String) -> Double {
|
||||
Double(cell(row, name)) ?? 0
|
||||
}
|
||||
switch page {
|
||||
case .slowQueries:
|
||||
return result.rows.prefix(100).enumerated().compactMap { position, row in
|
||||
let calls = number(row, "COUNT_STAR")
|
||||
let noIndex = number(row, "SUM_NO_INDEX_USED")
|
||||
let examined = number(row, "SUM_ROWS_EXAMINED")
|
||||
let sent = number(row, "SUM_ROWS_SENT")
|
||||
let digest = cell(row, "DIGEST_TEXT")
|
||||
let label = digest.isEmpty ? "Digest #\(position + 1)" : String(digest.prefix(110))
|
||||
if calls > 0 && noIndex > 0 {
|
||||
return "\(label): \(Int(noIndex)) of \(Int(calls)) executions reported no index usage. Inspect EXPLAIN and predicates."
|
||||
}
|
||||
if calls > 0 && examined > 10000 && sent < examined / 100 {
|
||||
return "\(label): high examined-to-returned row ratio. Check filters and index selectivity."
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case .tableIO:
|
||||
return result.rows.prefix(20).compactMap { row in
|
||||
let reads = number(row, "COUNT_READ")
|
||||
let writes = number(row, "COUNT_WRITE")
|
||||
guard reads + writes > 10000 else { return nil }
|
||||
let table = "\(cell(row, "OBJECT_SCHEMA")).\(cell(row, "OBJECT_NAME"))"
|
||||
return "\(table): \(Int(reads)) reads, \(Int(writes)) writes since counters were reset. Review workload before tuning."
|
||||
}
|
||||
case .innodbLocks:
|
||||
guard !result.rows.isEmpty else { return [] }
|
||||
return ["\(result.rows.count) lock-wait relationship(s) visible. Inspect active transactions before taking action."]
|
||||
case .connectionStatistics:
|
||||
let values = Dictionary(uniqueKeysWithValues: result.rows.compactMap { row -> (String, Double)? in
|
||||
guard row.count >= 2, let value = Double(row[1]) else { return nil }
|
||||
return (row[0], value)
|
||||
})
|
||||
var findings: [String] = []
|
||||
if (values["Aborted_connects"] ?? 0) > 0 {
|
||||
findings.append("Aborted connections recorded: \(Int(values["Aborted_connects"] ?? 0)). Check credentials, network failures and connection limits.")
|
||||
}
|
||||
if (values["Created_tmp_disk_tables"] ?? 0) > 0 {
|
||||
findings.append("Disk temporary tables recorded: \(Int(values["Created_tmp_disk_tables"] ?? 0)). Review heavy grouping and sorting queries.")
|
||||
}
|
||||
return findings
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
private var diagnosticReportText: String {
|
||||
(["DBSyn Database Diagnostics", page.rawValue, "Snapshot: \(Date().formatted())", "",
|
||||
"Advisory findings (cumulative counters; not proof of a defect):"] +
|
||||
(diagnosticFindings.isEmpty ? ["No threshold-based findings for this snapshot."] : diagnosticFindings))
|
||||
.joined(separator: "\n")
|
||||
}
|
||||
|
||||
private var filteredRows: [[String]] {
|
||||
guard !searchText.isEmpty else { return result.rows }
|
||||
return result.rows.filter { row in
|
||||
@@ -2907,6 +2971,35 @@ struct WorkbenchAdministrationView: View {
|
||||
.padding(.vertical, 8)
|
||||
}
|
||||
|
||||
if !diagnosticFindings.isEmpty && errorMessage == nil {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
HStack {
|
||||
Label("Diagnostic Findings", systemImage: "stethoscope")
|
||||
.font(.headline)
|
||||
Spacer()
|
||||
Button("Copy Report") {
|
||||
NSPasteboard.general.clearContents()
|
||||
NSPasteboard.general.setString(diagnosticReportText, forType: .string)
|
||||
}
|
||||
}
|
||||
ForEach(Array(diagnosticFindings.prefix(5).enumerated()), id: \.offset) { _, finding in
|
||||
Text("• " + finding)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
if diagnosticFindings.count > 5 {
|
||||
Text("\(diagnosticFindings.count - 5) additional findings available in Copy Report")
|
||||
.font(.caption2).foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(12)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(.quaternary.opacity(0.35), in: RoundedRectangle(cornerRadius: 8))
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 6)
|
||||
}
|
||||
|
||||
if supportsTrends && !diagnosticSamples.isEmpty && page != .dashboard && page != .serverStatus {
|
||||
HStack(spacing: 12) {
|
||||
Label("\(diagnosticSamples.count) samples", systemImage: "chart.xyaxis.line")
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Phase 69 — Database Diagnostics
|
||||
|
||||
Adds advisory diagnostics to the existing Server Administration monitoring pages.
|
||||
|
||||
- Slow Query Analysis: flags statement digests with reported non-index usage and high examined/returned row ratios.
|
||||
- Table I/O Hotspots: highlights heavily accessed tables based on cumulative Performance Schema counters.
|
||||
- InnoDB Lock Waits: displays a warning when blocking relationships are present.
|
||||
- Connection Statistics: flags aborted connections and disk-based temporary tables.
|
||||
- Copy Report exports the complete diagnostic findings for the current snapshot.
|
||||
|
||||
All findings are read-only, computed from existing server query results, and should be interpreted as investigation prompts rather than definitive tuning instructions. Thresholds are intentionally conservative. No automatic schema modifications, server setting changes or query execution are performed by the diagnostic layer.
|
||||
|
||||
The existing performance dashboards, introspection, SQL autocomplete, data synchronisation previews and appearance settings remain unchanged.
|
||||
|
||||
Validation: Swift source was statically inspected; macOS compilation and live MySQL runtime verification are outstanding.
|
||||
Reference in New Issue
Block a user