Skip to content

feat(table-health): report table and index health of the selected database - #3958

Merged
datlechin merged 10 commits into
TableProApp:mainfrom
J2TeamNNL:feat/table-health
Nov 1, 2026
Merged

datlechin merged 10 commits into
TableProApp:mainfrom
J2TeamNNL:feat/table-health

Conversation

@J2TeamNNL

@J2TeamNNL J2TeamNNL commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • New Database > Table Health tab, one per connection. Enabled only for PostgreSQL, MySQL and MariaDB, and dimmed in Agent mode.
  • Reports on the database selected in the sidebar, captured when a refresh starts. The model owns the read, so a pane switch neither drops the first load nor strands it. Every read runs in one withMetadataDriver(scope:) lease on a pooled connection, never the user's session, so a failing check cannot abort an open transaction. No database selected asks for one.
  • PostgreSQL (every schema): bloated tables, unused indexes, tables without a primary key, foreign keys without an index.
    • Unused skips unique, constraint and foreign key indexes, partition indexes a parent owns, materialized views and other sessions' pg_temp schemas.
    • A partitioned table is listed once; its foreign key fix is CREATE INDEX, since PostgreSQL refuses CONCURRENTLY there.
    • track_counts = off skips the bloat and unused checks and says why.
  • MySQL and MariaDB: unused indexes, redundant indexes, tables without a primary key.
    • Unused skips unique and full-text indexes (MATCH reads are not counted), an index that leads with a foreign key's columns on either end, from any database (InnoDB reads it uncounted and refuses to drop it, error 1553), and a table with no counted I/O, which is how a table setup_objects leaves out looks.
    • Skipped, with the reason, when performance_schema is off, the wait/io/table/sql/handler instrument or global_instrumentation consumer is disabled, or the database has no counted table I/O.
    • Redundant never names an index covered only by an invisible (MySQL) or ignored (MariaDB) one, and never a full-text index, whose parser STATISTICS does not show. Index rows group by exact name and key position, so case-distinct tables cannot split an index.
  • Each finding previews its fix, quoted by the driver, in the themed SQLStatementPreview. Nothing runs it: Open in Editor, Copy, Open Table.
  • No cap on findings.
  • Refresh (Cmd+R and the toolbar) now reloads Table Health, Server Dashboard, Query Insights, Users & Roles and object source tabs. It did nothing on those tabs. One AppEvents.tabRefreshRequested replaces versionHistoryRefreshRequested and tableListingRefreshRequested.
  • One showSingletonTab(_:) and QueryTabManager.addSingletonTab(_:) replace the four Server Dashboard, Users & Roles, Query Insights and Table Health copies.
  • PaneRefreshControls is shared by Query Insights and Table Health. VoiceOver now reads the last update time.
  • New tab kind tableHealth: AppleScript table health (TPkx), MCP snapshot tableHealth.
  • Docs: docs(features): add the Table Health page docs#147.

Screenshots

Table Health, light

Table Health, dark

Test plan

  • PostgreSQLTableHealthProviderTests, MySQLTableHealthProviderTests: parsing, fix SQL, partitioned fix, skipped checks, foreign key and invisible index rules, one failing check isolated, index catalog read once.
  • TableHealthViewModelTests: one lease on the browse scope with .bulk, a pane switch during the first load, no database, offline then online, failed check keeps findings, selection.
  • MainContentCoordinatorRefreshTests: Refresh reaches each self-loading tab and Users & Roles. MainMenuBuilderTests: engine gate and Agent mode.
  • apple/scripts/probes/check-table-health-catalogs.sh runs every query and fix against real servers: PASS on PostgreSQL 12.22 and 17.11, MySQL 8.4.13, MariaDB 10.5.29 and 11.8.9.

Fixes #3935

@datlechin datlechin changed the title feat(table-health): report table and index health per connection feat(table-health): report table and index health of the selected database Oct 31, 2026
@datlechin
datlechin merged commit 3a935e8 into TableProApp:main Nov 1, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Table health insights: bloated tables, unused and missing indexes

2 participants