Readyset Docs
Demos and TutorialsQueryPilot

Tutorial: Caching with the Accelerator

Enable the Accelerator plugin, watch it discover hot queries and create Readyset caches, and control what it may and may not cache.

The Accelerator is QueryPilot's caching plugin. Running in-process inside the Router (binary querypilot), it ranks your hottest query shapes from the Router's own statistics, creates caches for them on a Readyset deployment, and installs the routing rules that steer matching traffic to those caches. This tutorial enables it, walks through one discovery cycle, and shows the operational controls: dry run, warmup, the denylist, and the kill switch.

Prerequisites:

  • A Router deployment (see Getting Started).
  • A running Readyset deployment reachable from the Router, with credentials that can run SHOW READYSET STATUS, SHOW CACHES, and CREATE CACHE. Readyset is a separate product; if you do not have a deployment, contact hello@readyset.io.
  • The Accelerator is the one QueryPilot component that requires Readyset. Everything else works without it.

Add a Readyset pool and the plugin block.

The Accelerator only installs rules that target pools you explicitly grant it. Add both to querypilot.toml:

[pools.readyset]
username = "app"
password = "<your-password>"
backends = [{ host = "readyset.internal", port = 5433 }]

[plugins.accelerator]
enabled = true
interval_s = 10                  # discovery cycle cadence, seconds
dry_run = true                   # log decisions, mutate nothing (first rollout step)
database = "postgresql"
readyset_servers = [{ host = "readyset.internal", port = 5433 }]
readyset_user = "app"
readyset_password = "<your-password>"
min_execution = 5                # executions before a shape is a candidate
warmup_time_s = 60               # new rules stay disabled for this window
api_key = "<your-api-key>"

[plugins.accelerator.grants]
pools = ["readyset"]
max_owned_rules = 100

Restart the Router. The plugin runs its cycle every interval_s seconds on its own thread: health-check Readyset, drop denylisted caches, reconcile rules against existing caches, then discover new candidates from the Router's per-query-shape statistics (the same data served at GET /api/stats/digests). Configuration errors fail startup; runtime errors never affect query traffic. Key-by-key detail is in the configuration reference.

Generate load and watch candidates appear.

Run a query through the Router repeatedly, at least min_execution times:

for i in $(seq 1 20); do
  psql -h localhost -p 5433 -U app -d mydb \
    -c "SELECT * FROM orders WHERE customer_id = $((RANDOM % 100))" > /dev/null
done

Literal values do not matter: the Router normalizes queries to a fingerprint, so all twenty executions count toward one shape. Watch the plugin's view of the world on the admin API (metrics port + 1):

curl -s http://localhost:9091/api/v1/plugins/accelerator/candidates
curl -s http://localhost:9091/api/v1/plugins/accelerator/status

/candidates lists each shape with its threshold evaluation; /status reports loop health (last cycle time, result, consecutive errors). In dry_run mode the log shows what the plugin would cache. When the candidate list looks right, set dry_run = false and restart.

Watch a cache get created and promoted.

With dry_run off, the next cycle checks candidate support with EXPLAIN CREATE CACHE FROM <sql>, runs CREATE CACHE on Readyset, and installs a routing rule for the fingerprint:

curl -s http://localhost:9091/api/v1/plugins/accelerator/rules

New rules are installed disabled while Readyset warms the cache, then enabled once warmup_time_s elapses. You see the rule appear in /rules with its enabled flag false, then flip to true one warmup window later. Once enabled, confirm routing changed:

curl -s "http://localhost:9091/api/routing/test?sql=SELECT%20*%20FROM%20orders%20WHERE%20customer_id%20=%207"
# ... "target_pool": "readyset" ...

On the metrics side, sqp_qp_caches_created_total and sqp_qp_rules_added_total increment, and sqp_qp_last_success_timestamp_seconds advances every cycle; alert on the latter going stale (see metrics).

The plugin also fails safe: if Readyset becomes unhealthy (snapshot in progress, unreachable), the Accelerator disables the rules it owns so traffic flows to the source database, and re-enables them on recovery. It never touches rules it did not create.

Denylist a query.

Some queries must never be cached, whatever the statistics say. The denylist file (path set by denylist_path, one rule per line) gates discovery and retroactively removes caches and rules for newly denied shapes:

# deny one specific query shape
digest=0x9A3C0F12B44D21AA

# deny everything in a schema
db=internal

Use the hex digest as the Accelerator's REST endpoints (/candidates, /rules) report it. The file is re-read at each cycle start, so edits take effect without a restart.

Know the operational controls.

Mutating endpoints require the configured api_key in the X-QueryPilot-Api-Key header:

# Kill switch: stop all mutations, keep observing
curl -s -X POST -H "X-QueryPilot-Api-Key: change-me" \
  http://localhost:9091/api/v1/plugins/accelerator/actions/pause

# Resume
curl -s -X POST -H "X-QueryPilot-Api-Key: change-me" \
  http://localhost:9091/api/v1/plugins/accelerator/actions/resume

# Cache a specific fingerprint immediately, skipping the ranking queue.
# fingerprint_hash is the numeric hash from /api/routing/test or /candidates.
curl -s -X POST -H "X-QueryPilot-Api-Key: change-me" \
  -H "Content-Type: application/json" \
  -d '{"fingerprint_hash": 11114457943247356330}' \
  http://localhost:9091/api/v1/plugins/accelerator/actions/force-cache

# Drop one owned rule, by the same numeric hash
curl -s -X DELETE -H "X-QueryPilot-Api-Key: change-me" \
  http://localhost:9091/api/v1/plugins/accelerator/rules/11114457943247356330

Force-cache is gated: the fingerprint must exist in the current statistics, be SELECT-shaped, and not be denylisted.

GET /decisions keeps a ring buffer of recent cycle outcomes, and GET /audit records operator mutations made through this API. The full endpoint table is in the Accelerator guide.

The standalone binary

The same engine also ships as querypilot-accelerator, a standalone binary with its own TOML-syntax .cnf config. It runs one full cycle per invocation under an external scheduler and manages either a ProxySQL deployment or a Router deployment from the outside, through the Router's admin API. Use it when the deployment being managed is not the Router process you control, or when you already schedule ProxySQL maintenance jobs. The in-process form above is the default path; see the Accelerator guide for the standalone configuration, discovery ranking modes, and per-user targets.