H2StatsProvider over INFORMATION_SCHEMA (statements via QUERY_STATISTICS, sessions, blocking, connections, indexes, size, settings, approximated table rows and sizes, text plans); per-area provider capabilities with rules skipped where a provider lacks the data; a vendor registry with a seam for MySQL/MariaDB; provider-specific setup and health checks; an Enable statement statistics action; and the H2 plan guard (single SELECT/WITH only, side-effecting functions refused, EXPLAIN ANALYZE only for non-admin users, read-only connection, always rolled back). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
5.6 KiB
Changelog
All notable changes are documented here. This project follows Keep a Changelog and semantic versioning.
[Unreleased]
Added
- H2 2.x support (
H2StatsProvider) fromINFORMATION_SCHEMA: statement statistics fromQUERY_STATISTICS(when the database runs withQUERY_STATISTICS=TRUE), sessions with blocking and idle-in-transaction detection, connection counts, table row estimates and sizes, index definitions, settings, and text query plans (EXPLAIN;EXPLAIN ANALYZEonly for non-admin H2 users, since H2 has no read-only transaction: plans refuse side-effecting functions such asFILE_WRITE, DDL/DML keywords, user-defined aliases and multiple statements). The enterprise test server showed UNSUPPORTED on H2; it now collects. - Per-area capabilities (
StatsFeature): providers declare which statistics areas they can supply andProviderCapabilities.features()reports what is available on a connection. Snapshot cache-hit ratio and connection limit stay empty when the vendor has none, and analysis rules declare the areas they need (DbPerfRule.requires()) and are skipped on providers that cannot supply them, so H2 never gets "unused index" or "low cache hit" findings from missing counters. - Provider registry keyed by JDBC product name (
DbStatsProviders.register), withdocs/PROVIDERS.mddescribing what MySQL/MariaDB and SQLite would map to. - Enable statement statistics action on Settings (
dbPerfEnableStatementStatistics, manage settings): on H2 runsSET QUERY_STATISTICS_MAX_ENTRIES 1000andSET QUERY_STATISTICS TRUEas an admin; on PostgreSQL explains the manual extension setup. It is the qbit's only change to the monitored database and is explicit.
Changed
- Health and the Setup panel take their prerequisite checks and remedies from the backend's provider: PostgreSQL still names
pg_stat_statementsandpg_read_all_stats; H2 namesQUERY_STATISTICSand the admin role (new access codesNO_QUERY_STATISTICSandNOT_ADMIN). - The previous-snapshot baseline no longer depends on a PostgreSQL-only counter (it uses the database size every supported provider records).
Fixed
- Query-spike alerts no longer hold seven days of query snapshots as records on every snapshot evaluation (~230,000 rows at kof22's rate).
SnapshotEvaluatorreads the window in 1,000-row keyset pages and keeps only each statement's current interval time, latest capture time and earlier interval times as primitive doubles; the spike rule (twelve prior samples, median, absence after an hour) is unchanged. - The Attribution home panel no longer loads a day of attribution detail into the heap. It sums statements and time per unit and table in the database (at most 5,000 groups), so a render holds about a thousand aggregate rows instead of the roughly 570,000 detail rows (540 MB in PostgreSQL) that ran the kof22 web pod out of memory on 2026-10-16. The daily attribution rollup reads the day in 1,000-row keyset pages (
DbPerfStore.forEachPage), so worker memory is bounded by distinct dimension keys, not by the day's row count. The hourly analysis (dbPerfAnalyze) reads attribution the same way:RuleContext.window("attribution", ...)returns database sums per unit, table and operation instead of every detail row (it filled the kof22 worker heap to ~1.8 GB every hour). - Collection no longer stops at RUNNING on large production statement sets: list folding in the SQL normalizer is a linear token scan (the nested-repetition regular expressions overflowed the stack on 60 KB statements with long IN/VALUES lists). Any failure, including an
Error, now closes the run as FAILED with the exception class, logs it at ERROR (class and frame only, never SQL text) and raises the collection alert; runs left RUNNING by a crash are closed as FAILED after three intervals. - Only one runtime attributes per JVM: starting attribution on a newer instance (a hot swap, or repeated server starts in tests) stops the previous one, so old instances are never pinned by a forgotten listener and flusher.
- Each table has its own icon (the app icon is now
storage), so nav entries are distinguishable and do not repeat icons used elsewhere. - Home tables keep at most four columns with plain headers (readable at every width): secondary facts such as calls and mean time, the session's query text, and a unit's kind and top table move into a second line of the first cell.
Added
-
QQQ attribution and N+1 detection: a core statement execution listener (QQQ 4.1.0-RC.13) aggregates database time per route, scheduled job, process, table and statement shape in bounded memory, records repeated statement shapes per unit of work, and each pod flushes one batched insert per table every
attribution_flush_seconds. Hosts without QQQ's application launcher callDbPerfRuntime.of(instance).startAttribution()after startup. -
Secured database-performance tables, PostgreSQL statistics snapshots, daily rollups and configurable retention.
-
Audited PLAN/GENERIC and read-only ANALYZE query viewer with SQL validation, timeout, rollback and transient parameter handling.
-
Query plan statement action with readable plan text, cost, SQL Workbench link and a sanitized assistant prompt.
-
UI API extension 1.0.0 with overview, live activity, explain and statement lookup, plus its committed OpenAPI contract.
-
Eight full-width typed home panels with pagination, record links, guided empty states and permission-gated live activity.
-
Maven-versioned QBIT help bundle, complete metadata coverage checks, rule threshold guidance and adoption documentation.
-
PostgreSQL security acceptance tests and H2 API/widget fixtures.