Skip to content

Collector

The Collector is the only part of Query Doctor that touches your database. It reads the schema, the table statistics and the query text, sends them to your Query Doctor instance, and analyzes none of it: the planning and costing happen on the instance, against a Postgres of its own.

The image is ghcr.io/query-doctor/collector.

Monitor stands beside a live database and checks in once a minute. You do not start it. Connecting a database in the app stores the connection string, and the instance runs the container itself against that database. See Getting Started.

CI runs once inside a job, captures the queries that job’s tests executed against its own Postgres service, and reports the verdict back to the pull request. This is the one you run yourself, as a step in your workflow. See CI integration.

Both report over the same HTTP endpoint, and neither holds a socket open for anything to call back down.

  • Schema — tables, columns, indexes, constraints, functions, views, types, triggers, and extensions, read from the catalog.
  • Query statistics — recent queries and their execution metrics from the pg_stat_statements extension. Note that pg_stat_statements can contain real query text, including literal parameter values depending on your PostgreSQL configuration.
  • Table statistics — row estimates and the contents of pg_statistic, used for query plan analysis. These are real values read from your database.

Each read stands on its own. A database without pg_stat_statements still sends its schema and statistics; a statistics dump that fails on a statement timeout does not cost the check-in the queries it was about to deliver.

All three go to the Query Doctor instance the Collector was told to report to, which stores them against your project. That is https://cloud.querydoctor.com on the hosted service, or your own instance’s address if you self-host. The table statistics carry the most sensitive data: pg_statistic rows include the most common values and histogram bounds Postgres sampled from your columns, so they contain real values out of your tables.

The TOKEN the container carries authenticates that upload. No setting keeps the data on your machine.

Nothing. Both modes read.

Installing pg_stat_statements is yours to do. CREATE EXTENSION and ALTER SYSTEM SET shared_preload_libraries both need a superuser, so the app shows you the SQL when it notices the extension is missing.

Costing candidate indexes writes nothing here either. Query Doctor replays your schema into a Postgres of its own, creates the candidate indexes there, and throws the database away. Your rows never reach it: only the schema, the statistics and the query text are sent.

Variable What it is
SOURCE_DATABASE_URL The database to read. Required in both modes.
SITE_API_ENDPOINT The Query Doctor instance this run reports to. Required in both modes.
TOKEN The project’s analyzer token, which authorizes the upload. Required in monitor mode.
CI true selects CI mode. A container step does not inherit the runner’s, so a workflow sets it itself.

The container exits at startup without the first two. In monitor mode the instance fills all of them in; in CI they are the step’s env block, which CI integration shows whole.

  • pg_stat_statements extension — required for query statistics. Install it with:

    CREATE SCHEMA IF NOT EXISTS ext;
    CREATE EXTENSION IF NOT EXISTS pg_stat_statements SCHEMA ext;

    The Collector resolves the extension’s schema from pg_extension, so it reads the statistics wherever they are. Keep them out of public, where the extension’s views break migration tools that reconcile that schema (see Enabling pg_stat_statements).

    The extension must also be added to shared_preload_libraries in your PostgreSQL config, which requires a server restart.

  • Database access — the user in your connection string needs read access to the schema and the statistics views. Nothing the Collector does needs more than that.