--- title: Introduction description: Per-query telemetry for PostgreSQL, stored and analyzed in ClickHouse --- pg_stat_ch is a PostgreSQL extension that captures per-execution query telemetry and exports it to ClickHouse. Every query execution becomes a row in ClickHouse with timing, buffer usage, WAL activity, CPU time, JIT stats, error details, and client context. ## Why pg_stat_ch PostgreSQL ships with `pg_stat_statements`, which aggregates query statistics in shared memory. It answers "how does this query perform on average?" but cannot answer: - **When did it get slow?** Cumulative counters hide time-series trends. You can't see a latency spike that started 10 minutes ago. - **What happened during that one slow execution?** Averages smooth over outliers. A single 30-second query disappears into a mean of 5ms. - **Which application or user caused the load?** `pg_stat_statements` groups by query text, not by client. - **What errors are happening and when?** Error tracking is not part of `pg_stat_statements`. pg_stat_ch solves this by exporting raw, per-execution events to ClickHouse, where you can slice and aggregate the data however you need. | | pg_stat_statements | pg_stat_ch | |---|---|---| | **Granularity** | Cumulative per query | Per execution | | **Time-series** | No (counters only) | Yes (timestamped events) | | **Percentiles** | No | p50/p95/p99 via ClickHouse | | **Error tracking** | No | SQLSTATE, error level, message | | **Client attribution** | No | Application name, client IP | | **Storage** | PostgreSQL shared memory | ClickHouse (compressed, scalable) | | **Retention** | Resets on restart | Days, weeks, or longer | | **Query overhead** | ~1-2 us | ~5 us p99 | ## Architecture ```mermaid graph LR A["PostgreSQL hooks
(foreground)"] --> B["Shared-memory
ring buffer"] B --> C["Background worker
(exporter)"] C --> D["ClickHouse
events_raw"] D --> E["Materialized views
(aggregation)"] ``` 1. **Hooks** capture query telemetry in the foreground path. The extension hooks into `ExecutorStart`, `ExecutorRun`, `ExecutorFinish`, `ExecutorEnd`, `ProcessUtility`, and `emit_log` to collect timing, buffer stats, WAL usage, CPU time, JIT metrics, errors, and client context. 2. **Shared-memory ring buffer** receives events with no network I/O on the query path. The buffer uses a multi-producer, single-consumer (MPSC) design with batched writes. 3. **Background worker** drains the ring buffer and inserts events to ClickHouse in batches. It runs on a configurable interval (default 200ms) with automatic retry and exponential backoff. 4. **ClickHouse materialized views** handle all aggregation. Pre-built views provide 5-minute query stats with percentiles, per-application load breakdowns, and error feeds. You can add your own views for custom analytics. ## What it captures Every query execution produces an event with these fields: | Category | Fields | Notes | |---|---|---| | **Timing** | `ts_start`, `duration_us` | Microsecond precision | | **Identity** | `db`, `username`, `pid`, `query_id`, `cmd_type` | `query_id` groups normalized queries | | **Results** | `rows`, `query` | Query text truncated to 2 KB | | **Shared buffers** | `shared_blks_hit/read/dirtied/written` | Cache hit ratio | | **Local buffers** | `local_blks_hit/read/dirtied/written` | Temp table I/O | | **Temp files** | `temp_blks_read/written` | `work_mem` pressure | | **I/O timing** | `shared/local/temp_blk_read/write_time_us` | Requires `track_io_timing=on` | | **WAL** | `wal_records`, `wal_fpi`, `wal_bytes` | Write-ahead log activity | | **CPU** | `cpu_user_time_us`, `cpu_sys_time_us` | User vs kernel time | | **JIT** | `jit_functions`, `jit_*_time_us` | JIT compilation overhead (PG 15+) | | **Parallel** | `parallel_workers_planned/launched` | Worker efficiency (PG 18+) | | **Errors** | `err_sqlstate`, `err_elevel`, `err_message` | SQLSTATE code and severity | | **Client** | `app`, `client_addr` | Load attribution | See the [events schema reference](/reference/events-schema) for the full field list with types and tuning guidance. ## Supported versions - PostgreSQL 16, 17, and 18 - ClickHouse (any recent version) or OpenTelemetry-compatible collectors Newer PostgreSQL versions expose additional metrics. See [version compatibility](/reference/version-compatibility) for the feature matrix. ## Next steps Build from source and load the extension End-to-end setup in 5 minutes with Docker