Skip to content

Commit ee1351e

Browse files
feat: enable prepared statement caching via statementNameGenerator
Add deterministic prepared statement names (SHA-256 hash of SQL) to both writer and replica PrismaPg adapters. This lets PostgreSQL reuse cached query plans instead of parsing and planning every query from scratch. The old Rust engine did this automatically; the driver adapter requires explicit opt-in via the statementNameGenerator option (added in v7.6.0). Co-Authored-By: Eric Allam <eallam@icloud.com>
1 parent 04bb2ce commit ee1351e

1 file changed

Lines changed: 26 additions & 12 deletions

File tree

apps/webapp/app/db.server.ts

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
type PrismaTransactionOptions,
99
} from "@trigger.dev/database";
1010
import { PrismaPg } from "@prisma/adapter-pg";
11+
import { createHash } from "node:crypto";
1112
import invariant from "tiny-invariant";
1213
import { z } from "zod";
1314
import { env } from "./env.server";
@@ -117,12 +118,20 @@ function getClient() {
117118

118119
console.log(`🔌 setting up prisma client to ${redactUrlSecrets(databaseUrl)}`);
119120

120-
const adapter = new PrismaPg({
121-
connectionString: databaseUrl.href,
122-
max: env.DATABASE_CONNECTION_LIMIT,
123-
idleTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
124-
connectionTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
125-
});
121+
const adapter = new PrismaPg(
122+
{
123+
connectionString: databaseUrl.href,
124+
max: env.DATABASE_CONNECTION_LIMIT,
125+
idleTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
126+
connectionTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
127+
},
128+
{
129+
// Generate deterministic prepared statement names from query SQL so PostgreSQL
130+
// can reuse cached query plans. Without this, every query uses an anonymous
131+
// prepared statement that PG must parse and plan from scratch each time.
132+
statementNameGenerator: (query) => `p_${createHash("sha256").update(query.sql).digest("hex").slice(0, 16)}`,
133+
}
134+
);
126135

127136
const client = new PrismaClient({
128137
adapter,
@@ -240,12 +249,17 @@ function getReplicaClient() {
240249

241250
console.log(`🔌 setting up read replica connection to ${redactUrlSecrets(replicaUrl)}`);
242251

243-
const adapter = new PrismaPg({
244-
connectionString: replicaUrl.href,
245-
max: env.DATABASE_CONNECTION_LIMIT,
246-
idleTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
247-
connectionTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
248-
});
252+
const adapter = new PrismaPg(
253+
{
254+
connectionString: replicaUrl.href,
255+
max: env.DATABASE_CONNECTION_LIMIT,
256+
idleTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
257+
connectionTimeoutMillis: env.DATABASE_CONNECTION_TIMEOUT * 1000,
258+
},
259+
{
260+
statementNameGenerator: (query) => `p_${createHash("sha256").update(query.sql).digest("hex").slice(0, 16)}`,
261+
}
262+
);
249263

250264
const replicaClient = new PrismaClient({
251265
adapter,

0 commit comments

Comments
 (0)