Skip to content

boltPlan cache ​

Running a SPARQL query costs two things: translating the SPARQL into SQL, and running that SQL. Each connection caches its translations, so a repeated query pays only for running it. There is nothing to configure.

What counts as the same query ​

The cache is keyed on the shape of the query, not its exact text:

  • Whitespace and layout don't matter.
  • Queries that differ only in constants (IRIs, literals, numbers) share one entry. Each run still uses its own values.
  • A different shape (another triple pattern, a FILTER, an aggregate) gets its own entry.

In a new connection, over the graph from Composing with SQL:

sql
SELECT pgrdf.stats() -> 'plan_cache_local_size';   -- 0

SELECT sparql->>'o' AS o FROM pgrdf.sparql('PREFIX foaf: <http://xmlns.com/foaf/0.1/>
  SELECT ?o WHERE { <http://example.com/alice> foaf:knows ?o }');   -- bob, carol
SELECT sparql->>'o' AS o FROM pgrdf.sparql('PREFIX foaf: <http://xmlns.com/foaf/0.1/>
  SELECT ?o WHERE { <http://example.com/bob> foaf:knows ?o }');     -- carol
SELECT pgrdf.stats() -> 'plan_cache_local_size';   -- 1: same shape, one entry

SELECT sparql FROM pgrdf.sparql('PREFIX foaf: <http://xmlns.com/foaf/0.1/>
  SELECT ?p (COUNT(?o) AS ?c) WHERE { ?p foaf:knows ?o } GROUP BY ?p ORDER BY ?p');
SELECT pgrdf.stats() -> 'plan_cache_local_size';   -- 2: a new shape

Your application can build queries with different constants freely, without flooding the cache.

Cached queries see current data ​

A cached translation runs against the data as it is now. Graphs added, loaded or cleared after a query was cached show up in its next run. You don't need to invalidate anything after changing data.

One cache per connection ​

Each connection's cache starts empty when the connection opens and disappears when it closes. A connection pool keeps connections, and their caches, alive between requests. Opening a new connection for every query makes every query pay for translation.

Watching it ​

sql
SELECT s->'plan_cache_local_size' AS this_connection,
       s->'plan_cache_hits'       AS hits_all_connections,
       s->'plan_cache_misses'     AS misses_all_connections
  FROM pgrdf.stats() AS s;

plan_cache_local_size counts this connection's entries. The hit and miss counters are cumulative across all connections on the server; see Counters and health.

plan_cache_clear() exists as an internal diagnostic; see Cache control. Closing the connection has the same effect.

See also ​

pgRDF is released under the MIT license. Documentation built with VitePress, served via GitHub Pages.