Skip to content
Open
2 changes: 1 addition & 1 deletion docs/providers/clickhouse.md
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,7 @@ keep surfacing.
| `getOverview()` | `version()`, `uptime()`, `system.metrics`, `system.server_settings`, `system.parts`, `system.tables`, `system.data_skipping_indices` | Five separate reads on purpose: a restricted user gets `200` from `version()`/`uptime()` and `system.tables`, but `500`/497 from `system.metrics` and the two count queries — combining them into one statement would throw away the panels a restricted user CAN see |
| `getPerformanceMetrics()` | `system.events` (`MarkCacheHits`/`MarkCacheMisses`/`Query`), `system.asynchronous_metrics` (`MemoryResident`/`OSMemoryTotal`) | cache-hit ratio from the mark cache (ClickHouse's nearest buffer-cache equivalent); `queriesPerSecond` divides the lifetime `Query` counter by uptime, since neither is ever sampled twice in a single-shot read; buffer-pool usage is resident memory against total machine memory |
| `getSlowQueries()` | `system.query_log` where `type = 'QueryFinish'`, grouped by `normalized_query_hash` | Grouped the way `pg_stat_statements` groups — one row per statement *shape*, with its call count and min/max/avg duration, not one row per execution. Flushed **asynchronously**, so a statement that just ran may be absent for a few seconds |
| `getActiveSessions()` | `system.processes` | Excludes its own read (`query NOT LIKE '%system.processes%'`), the same trick `postgres.ts` applies to `pg_stat_activity`; every row is reported with a constant `state: "active"`, because ClickHouse has no idle-in-transaction equivalent to distinguish |
| `getActiveSessions()` | `system.processes` | Excludes its own read (`query NOT LIKE '%system.processes%'`), the same trick `postgres.ts` applies to `pg_stat_activity`; every row is reported with `state` and `activity` `active`, because ClickHouse has no idle-in-transaction equivalent to distinguish |
| `getTableStats()` / `getIndexStats()` | `system.parts` (active parts only) / `system.data_skipping_indices` | Accept an optional `{ schema }` filter; without one, every non-system database is covered. Index scan counts are always `0` — ClickHouse publishes no per-index usage counter anywhere, and a guessed number would be worse than an obvious zero |
| `getStorageStats()` | `system.disks` | Name, path, total/free bytes, and a usage percentage per configured disk |
| `getHealth()` | the four above, composed | connections, size, cache-hit ratio, top-5 slow queries, top-10 sessions |
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/databend.md
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ When Databend answers one of the codes 1003, 1025, 1063, 1112, 1119 or 1002 (an
- Overview: the version is `version()`; uptime is "unknown" and the connection limit 0, because Databend publishes neither; the size is the compressed data plus index size of the default catalog's base tables, "N/A" when that read degraded; the active count is the running statements of `system.processes`, Studio's own statements left out (below).
- Sessions: one row per running statement of the server or warehouse, every user's included, from `system.processes`, which needs no grant, since Databend creates a session per HTTP request.
The kill target is the row's session id.
Its state is "active" while it runs a statement (`command` `Query`), the word the Active card and the Overview count, and "aborting" (`Aborting`) while a `KILL CONNECTION` or a server shutdown ends its session; the panel's own kill, a `KILL QUERY`, leaves it "active" until the statement stops.
Its state is "active" while it runs a statement (`command` `Query`) and "aborting" (`Aborting`) while a `KILL CONNECTION` or a server shutdown ends its session; the panel's own kill, a `KILL QUERY`, leaves it "active" until the statement stops. `activity` is `active` for `Query` and `other` for any other command, and the Active and Idle cards count `activity`.
Databend's query id of the statement is not shown: a session row of the panel has no field for one.
Studio's own statements are left out (below).
- Slow queries: `system_history.query_history`, the finished statements of the last 24 hours, slowest first.
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/mongodb.md
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ Every method is wrapped in try/catch. Degradation reports the absence rather tha
| `getOverview()` | `serverStatus`, `buildInfo`, `dbStats`, `listCollections` | version, uptime, connections (**omitted**, never `0`, on the same two paths as `getHealth()`, [§7.2](#72-a-connection-count-nobody-published-is-absent-not-zero)), database size (**`dataSize + indexSize`**, the database-level sums of the per-collection `collStats.size` and `totalIndexSize` the rows are built from, so a share's numerator and denominator are the same pair; `databaseSizeBytes` **omitted**, never `0`, when either addend is unpublished, [§7.3](#73-a-database-size-nobody-published-is-absent-not-0-b)), collection/index counts. `maxConnections` is `connections.current + connections.available`, or `0` (the repo's spelling of *no limit published*) when the server publishes no headroom |
| `getPerformanceMetrics()` | `serverStatus` (WiredTiger + opcounters) | cache-hit %, **ops/sec** (`query`+`insert`+`update`+`delete` opcounters ÷ uptime — *total operations, not just queries*), buffer-pool % (cache bytes), `deadlocks: 0`. **Every field is optional**: each one is present only if its reading was, and a failed `serverStatus` reports `{}` ([§7.1](#71-what-the-panel-shows-when-the-cache-cannot-be-measured)) |
| `getSlowQueries()` | `system.profile` | per-op time/returned; **`[]` if the profiler isn't enabled** (`db.setProfilingLevel(1)`); sorted by `millis` (slowest) — note `getHealth()`'s slow-query block instead sorts by `ts` (most recent) and emits a placeholder row when disabled |
| `getActiveSessions()` | `currentOp` | opid, ns, lock waits, duration — ⚠️ the **`user` field is populated from `op.client`** (the client `host:port`), **not** an authenticated user |
| `getActiveSessions()` | `currentOp` | opid, ns, lock waits, duration. `activity` is `active` when the operation's `active` flag is set and `idle` when it is not — ⚠️ the **`user` field is populated from `op.client`** (the client `host:port`), **not** an authenticated user |
| `getTableStats()` | `collStats` per collection | row count + data/index/total sizes, `totalIndexSize` carried as the byte figure `indexSizeBytes` and not only as formatted text; a time series collection is **one** row, because the server's internal `system.buckets.<name>` duplicate is skipped rather than summed beside it; every other `system.*` namespace (`system.views` included) is skipped with the same `system.` prefix the object browser uses, so Monitoring lists the same collections the tree does. `systemetrics` does not start with that prefix and stays |
| `getIndexStats()` | `$indexStats` + `indexes()` | **real `scans`** (`accesses.ops`); `indexSize` `N/A`; **`indexType` only distinguishes `text` vs `btree`** — `hashed`/`2dsphere`/`2d`/wildcard/clustered are all mislabelled `btree` |
| `getStorageStats()` | `dbStats` + WiredTiger | Data / Indexes / Storage / WiredTiger cache (with usage %) |
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/mssql.md
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,7 @@ in parallel. Each sub-query is independently privilege-guarded (DMVs need `VIEW
| `getOverview()` | `@@VERSION`, `dm_os_sys_info`, `dm_exec_sessions`, `sys.configurations`, `database_files`, `sys.tables`/`indexes` | `user connections = 0` → reported as 32767 (unlimited); `databaseSizeBytes` is **omitted** and `databaseSize` stays `N/A`, never a `0`, when the size statement fails — [§8.3](#83-when-the-database-size-is-not-measurable) |
| `getPerformanceMetrics()` | `dm_os_performance_counters` | **only** the cache-hit ratio, and it is **omitted** when the DMV cannot be read (no QPS/deadlocks/buffer-pool) — [§8.1](#81-when-the-cache-hit-ratio-is-not-measurable) |
| `getSlowQueries()` | `dm_exec_query_stats` ⋈ `dm_exec_sql_text` | `sharedBlksHit`=logical reads, `sharedBlksRead`=physical reads; `[]` on failure |
| `getActiveSessions()` | `dm_exec_sessions` ⋈ `dm_exec_requests` ⋈ `dm_exec_sql_text` | **`blocked` is real** (`blocking_session_id > 0`); wait types; `[]` on failure |
| `getActiveSessions()` | `dm_exec_sessions` ⋈ `dm_exec_requests` ⋈ `dm_exec_sql_text` | **`blocked` is real** (`blocking_session_id > 0`); wait types; `[]` on failure. `activity` classifies `status`: `sleeping` and `dormant` are `idle`, `suspended` is `waiting`, `running` or `runnable` is `waiting` only while `wait_type` is set, and any other status is `other`. The raw status stays in `state` |
| `getTableStats()` | `sys.tables`/`partitions`/`allocation_units` | sizes + `lastAnalyze` (`STATS_DATE`); no live/dead tuples; `[]` on failure |
| `getIndexStats()` | `sys.indexes`/`allocation_units` + `dm_db_index_usage_stats` | **`scans` is real** (seeks+scans+lookups); `[]` on failure |
| `getStorageStats()` | `sys.database_files` | per-file name/path/size; `[]` on failure |
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/mysql.md
Original file line number Diff line number Diff line change
Expand Up @@ -1927,7 +1927,7 @@ All monitoring reads from `SHOW STATUS`/`SHOW VARIABLES`, `information_schema`,
| `getOverview()` | `VERSION()`, one bare `SHOW STATUS` (`Uptime` and `Threads_connected` out of the same result), `SHOW VARIABLES LIKE 'max_connections'`, `information_schema` | version, uptime, conns, max_conns, size, table/index counts |
| `getPerformanceMetrics()` | `performance_schema.global_status`, one bare `SHOW STATUS` (`Innodb_deadlocks` picked client-side) | cache-hit %, **queries/sec** (`Queries`/`Uptime`), buffer-pool %, deadlocks. Every field optional — see the degradation note below |
| `getSlowQueries()` | `performance_schema.events_statements_summary_by_digest` | per-digest stats |
| `getActiveSessions()` | `information_schema.PROCESSLIST` | pid, user, db, host, command, duration |
| `getActiveSessions()` | `information_schema.PROCESSLIST` | pid, user, db, host, command, duration. `activity` classifies `COMMAND`: `Query` is `active`, `Sleep` is `idle`, and every other command (`Daemon` included) is `other`. The raw command stays in `state` |
| `getTableStats()` | `information_schema.TABLES` | sizes; bloat **estimated from `DATA_FREE`** (no live/dead tuples, no last-vacuum/analyze) |
| `getIndexStats()` | `information_schema.STATISTICS` + `mysql.innodb_index_stats` | columns, unique/primary; **`scans` = `CARDINALITY`** (a proxy, not a real scan counter); per-index size, or **absent** — see the index-size note below |
| `getStorageStats()` | `information_schema.TABLES`, `SHOW BINARY LOGS` | Data size, Binary Logs (if enabled), InnoDB data file (size `N/A`) |
Expand Down
1 change: 1 addition & 0 deletions docs/providers/neo4j.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ No kind declares `acceptsSourceEdits` or `acceptsRowWrites`: there is no source

The transactions read names its columns, never the `parameters` column, which can hold a secret, and never `YIELD *`.
Each `elapsedTime` is read as an ISO 8601 duration of days and time, a sign allowed on each component, and a negative total is shown as 0 ms (#1416): Neo4j 2026.09.0 reported a just-started transaction as `PT-0.001000000S` on about one Sessions load in three, and refusing that value dropped the whole panel. Any other text in that column still refuses the panel, naming the column.
A transaction's `activity` is `active` while `status` is `Running` and `other` for `Blocked`, `Closing` and `Terminated`. The row shows `Running` as "active" and any other status lower-cased, and the Active and Idle cards count `activity`.
Each label in a count statement is backticked by the quoting module and checked by the read policy before it runs; a label the quoting refuses is left out, and the server log names every label left out, since the table stats have no field to say so.
The monitoring reads run through the same READ session path without the user's policy, and a unit test checks every one against the policy: every monitoring read but the transactions read passes it.
The transactions read stays out of the user allowlist (section 3.2), since a user's `SHOW TRANSACTIONS YIELD *` returns other sessions' query text and parameters, and the monitoring read keeps a fixed column list that names no `parameters` column.
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/oracle.md
Original file line number Diff line number Diff line change
Expand Up @@ -1969,7 +1969,7 @@ are not ([§3.7](#37-privilege-resilient-monitoring)).
| `getOverview()` | `V$VERSION`, `V$INSTANCE`, `V$SESSION`, `V$PARAMETER`, `USER_SEGMENTS`, `USER_TABLES`/`USER_INDEXES` | each guarded; `activeConnections` is **omitted**, never `0` ([§7.2](#72-when-the-connection-count-is-not-measurable)), while `maxConnections` stays `0` because `0` there means "no limit published"; `databaseSizeBytes` is **omitted** and `databaseSize` stays `N/A`, never a `0`, when `USER_SEGMENTS` does not answer ([§7.3](#73-when-the-database-size-is-not-measurable)) |
| `getPerformanceMetrics()` | `V$SYSSTAT` | **only** `cacheHitRatio`, and it is **omitted** when `V$SYSSTAT` cannot be read (no QPS/deadlocks/buffer-pool) — [§7.1](#71-when-the-cache-hit-ratio-is-not-measurable) |
| `getSlowQueries()` | `V$SQL` (top-N by `ELAPSED_TIME`) | `sharedBlksHit`=`BUFFER_GETS`, `sharedBlksRead`=`DISK_READS`; `[]` on failure |
| `getActiveSessions()` | `V$SESSION` ⋈ `V$SQL` | `pid` = `"SID,SERIAL#"`; wait class/event; `[]` on failure |
| `getActiveSessions()` | `V$SESSION` ⋈ `V$SQL` | `pid` = `"SID,SERIAL#"`; wait class/event; `[]` on failure. `activity` classifies `STATUS` and `STATE`: `INACTIVE` is `idle` even when `WAIT_CLASS` is set, `ACTIVE` is `waiting` only when `STATE` is `WAITING` and the wait class is other than `Idle` (`EVENT` and `WAIT_CLASS` keep the last wait once the session is on CPU, and there is no CPU wait class), and any other status is `other`. The raw status stays in `state` |
| `getTableStats()` | `USER_TABLES` + `USER_LOBS` + `USER_INDEXES` + `USER_SEGMENTS` | one row per table the connected user owns; sizes + `lastAnalyze` ([§7.4](#74-what-a-tables-size-counts)); no live/dead tuples, no bloat; **rejects** with the engine's sentence on failure ([§3.7](#37-privilege-resilient-monitoring)) |
| `getIndexStats()` | `ALL_INDEXES` + `USER_SEGMENTS` + `ALL_IND_COLUMNS` | size summed over every segment of the index, partitions included; **`scans` always `0`** (no usage counter exposed); `isPrimary` always `false`; **rejects** on failure |
| `getStorageStats()` | `DBA_DATA_FILES` → fallback `USER_SEGMENTS` | per-tablespace size; DBA view falls back to user segments without privilege |
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/postgres.md
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,7 @@ base) fans these out in parallel.
| `getOverview()` | `version()`, `pg_postmaster_start_time()`, `pg_settings`, `pg_database_size`, `information_schema.tables`/`pg_indexes` | version, uptime, conns, max_conns, size, table/index counts |
| `getPerformanceMetrics()` | `pg_statio_user_tables`, `pg_stat_database`, `pg_stat_checkpointer` (17+) or `pg_stat_bgwriter` | cache-hit % (omitted when unmeasurable), deadlocks, checkpoint write time (`N/A` when unreadable); **no buffer-pool %** — see [§7.1](#71-when-the-cache-hit-ratio-is-not-measurable) |
| `getSlowQueries()` | `pg_stat_statements` → fallback `pg_stat_activity` | detailed per-statement stats; fallback shows live active queries |
| `getActiveSessions()` | `pg_stat_activity` | pid, user, state, query, wait events, duration; excludes own backend |
| `getActiveSessions()` | `pg_stat_activity` | pid, user, state, query, wait events, duration; excludes the querying backend and every connection whose `application_name` is `libredb-studio`. `activity` is `waiting` only for an `active` session whose `wait_event_type` is set and is not `Client`; an idle session waiting on `Client` stays `idle`. Duration is measured to `clock_timestamp()`, so a statement that started after the reading transaction does not read below zero |
| `getTableStats()` | `pg_stat_user_tables` + `pg_table_size`/`pg_indexes_size`/`pg_total_relation_size`, each on `relid`; `pg_class` when that view answers no rows (#1540) | live/dead tuples, sizes (absent per function the engine refuses, [§3.1.2](#312-two-kinds-of-absence-and-why-neither-is-an-empty-array)), last (auto)vacuum/analyze, bloat ratio |
| `getIndexStats()` | `pg_stat_user_indexes`, `pg_index`, `pg_am` | type, columns, unique/primary, size, scan count, usage ratio |
| `getStorageStats()` | `pg_tablespace`, WAL functions | per-tablespace size; WAL size (superuser-gated, swallowed if denied) |
Expand Down
4 changes: 3 additions & 1 deletion docs/providers/redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ is not.
`getActiveSessions()` ([`redis.ts`](../../src/lib/db/providers/keyvalue/redis.ts)) splits each
line into `key=value` pairs and substitutes a default for anything missing: the session's user is
`user` falling back to `default`, its pid `id` falling back to `0`, its state `flags` falling back
to `N`, its command `cmd` falling back to `idle`. A relative that omits a field therefore produces a
to `N`, its command `cmd` falling back to `idle`. `activity` reads those flags: a flag string
containing `b` (the client is blocked) is `waiting`, and every other flag, including the fallback
`N`, is `idle`. A relative that omits a field therefore produces a
plausible-looking row rather than an error.

Three relatives diverge, all measured on the versions above:
Expand Down
2 changes: 1 addition & 1 deletion docs/providers/sqlite.md
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,7 @@ Minimal by nature — SQLite keeps almost no server-style runtime statistics.
| `getOverview()` | `sqlite_version()`, file size, `sqlite_master` counts | `uptime: N/A`, `maxConnections: 1`; `databaseSizeBytes` is **omitted** and `databaseSize` stays `N/A`, never a `0`, when the size read fails — [§7.3](#73-when-the-database-size-is-not-measurable) |
| `getPerformanceMetrics()` | — | **no cache-hit ratio, no QPS, no buffer-pool usage** — all three are omitted, so both monitoring tabs show "N/A / Not measured" for them ([§7.1](#71-there-is-no-cache-hit-ratio-and-there-cannot-be)); only `deadlocks: 0` is reported, which is a fact about the engine |
| `getSlowQueries()` | — | always `[]` (SQLite has no query stats) |
| `getActiveSessions()` | — | the single current process session |
| `getActiveSessions()` | — | the single current process session; `state` and `activity` are both `active` |
| `getTableStats()` | `COUNT(*)` per table, `dbstat` for the bytes | size is **measured page bytes wherever `dbstat` is compiled in, and absent where it is not** — see [§7.2](#72-per-table-size-depends-on-the-sqlite-build-behind-the-driver) |
| `getIndexStats()` | `PRAGMA index_list`/`index_info` | `scans` always `0` (no usage counter); `indexSize` is `N/A` and `indexSizeBytes` is **omitted** — SQLite publishes no per-index size, and a `0` was summed by the Storage tab as an empty index |
| `getStorageStats()` | `fs.statSync` on the DB / `-wal` / `-shm` files | per-file sizes (on disk only) |
Expand Down
Loading
Loading