README
¶
PredictiveCache Demo
This directory contains a working PostgreSQL example and an integration guide for an existing Go service.
Run the Demo
Prerequisites:
- Go 1.22 or newer;
- PostgreSQL command-line tools
initdbandpg_ctlonPATH; - a C compiler for the default
pg_query_goPostgreSQL parser build.
Docker is not required. From the repository root:
./scripts/run-demo.sh
The script uses /tmp by default. Set PCACHE_TMPDIR to another existing
short-path directory if needed.
The script creates a disposable PostgreSQL cluster under the system temporary
directory, runs postgres/main.go, and removes the cluster.
The program:
- creates user and order tables;
- trains a repeated user-to-orders query transition;
- shows the predicted template and argument binding;
- triggers a real background PostgreSQL prefetch;
- proves the next orders query was served from the in-memory cache.
The final line should be:
DEMO PASS: a learned transition executed on PostgreSQL in the background and served the next query from cache
Add It to an Existing Project
Install the module:
go get github.com/Hetul3/PredictiveCache@latest
go get github.com/jackc/pgx/v5
Register pgx with database/sql, open the existing database handle, and wrap
it once at application startup:
import (
"database/sql"
"time"
"github.com/Hetul3/PredictiveCache"
_ "github.com/jackc/pgx/v5/stdlib"
)
db, err := sql.Open("pgx", dsn)
if err != nil {
return err
}
pc, err := predictivecache.Wrap(
db,
predictivecache.DialectPostgres,
predictivecache.WithCacheTTL(5*time.Second),
predictivecache.WithMaxCacheBytes(64<<20),
predictivecache.WithPrefetchEnabled(true),
)
if err != nil {
return err
}
defer pc.Close()
Replace read calls with pc.QueryContext. The return type is
*predictivecache.Rows, which supports Next, Scan, Columns,
ColumnTypes, Err, Close, and FromCache:
ctx := predictivecache.WithSessionID(r.Context(), requestID)
ctx = predictivecache.WithRoute(ctx, "GET /users/:id")
rows, err := pc.QueryContext(
ctx,
"select id, name from users where id = $1",
userID,
)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var id int64
var name string
if err := rows.Scan(&id, &name); err != nil {
return err
}
}
if err := rows.Err(); err != nil {
return err
}
Run writes through pc.ExecContext so table-version invalidation occurs:
_, err = pc.ExecContext(
ctx,
"update users set name = $1 where id = $2",
name,
userID,
)
If another connection, process, or service writes to the database, notify this client before relying on cached reads:
err := pc.InvalidateTables("users", "orders")
// Use pc.InvalidateAll() when the affected tables are unknown.
Give the Predictor Useful Context
Use one session ID for the related queries in a request or workflow. A route helps distinguish code paths that begin with the same query:
ctx = predictivecache.WithSessionID(ctx, traceID)
ctx = predictivecache.WithRoute(ctx, "GET /users/:id")
ctx = predictivecache.WithTenant(ctx, tenantID)
When a later query needs a value that is not available from the previous query's arguments, supply it explicitly:
ctx = predictivecache.WithBindValue(ctx, "user_id", userID)
The library never executes a predicted query unless every argument has a high-confidence binding.
Tune It Safely
Prefetching is off by default. Start with exact caching, collect metrics, and enable prefetch only for repeated, bindable query flows with enough delay for a background query to finish.
Useful controls:
predictivecache.WithMinEventsBeforePrefetch(500)
predictivecache.WithPredictionConfidenceThreshold(0.70)
predictivecache.WithBindingMinTrials(5)
predictivecache.WithBindingConfidenceThreshold(0.85)
predictivecache.WithPrefetchConcurrency(2)
predictivecache.WithPrefetchMaxQPS(20)
predictivecache.WithPrefetchTimeout(500 * time.Millisecond)
Inspect behavior rather than assuming prefetch is helping:
stats := pc.Stats()
explain, err := pc.Explain(ctx, query, args...)
Pay particular attention to cache hit-rate lift, PrefetchHits,
PrefetchWasted, PrefetchErrors, and rejection counters. Disable prefetch
when it raises database load without improving application latency.
Persistence and Privacy
Learned metadata persistence is opt-in:
predictivecache.WithLogDir("./.predictivecache")
Persistence excludes sessions, argument values, result rows, and cache entries.
Original executable SQL is also excluded unless
WithPersistRawSQL(true) is set. Review SQL text for sensitive literals before
enabling that option.
Current Boundaries
- PostgreSQL is the only supported dialect.
- Explicit transaction caching and prefetching are not supported in v1.
- The API is a DB-like wrapper, not a transparent
database/sql/driver. - External writes require explicit invalidation.
- The no-cgo parser fallback has intentionally narrower SQL coverage and disables structural cold-start fallback.