From d2b28a1164a126c19ba52e0ed99da86bd73ec7d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Mon, 25 May 2026 23:59:10 +0200 Subject: [PATCH] fix(planner): add index on sessions.last_activity for the expire job The hourly `expireSessions()` cron runs `DELETE FROM planner.sessions WHERE last_activity < cutoff`. Without an index on `last_activity`, that's a full table scan growing linearly with the total sessions ever created (planner sessions are never user-deleted; expiry is the only churn path). `drizzle-kit push` picks this up on next deploy. --- packages/db/src/schema/planner.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/db/src/schema/planner.ts b/packages/db/src/schema/planner.ts index d789283..a797ef4 100644 --- a/packages/db/src/schema/planner.ts +++ b/packages/db/src/schema/planner.ts @@ -1,4 +1,4 @@ -import { pgSchema, text, timestamp, boolean, customType } from "drizzle-orm/pg-core"; +import { pgSchema, text, timestamp, boolean, customType, index } from "drizzle-orm/pg-core"; const bytea = customType<{ data: Buffer }>({ dataType() { @@ -16,4 +16,9 @@ export const sessions = plannerSchema.table("sessions", { createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), lastActivity: timestamp("last_activity", { withTimezone: true }).notNull().defaultNow(), closed: boolean("closed").notNull().default(false), -}); +}, (t) => ({ + // Hourly `expireSessions()` job runs `DELETE WHERE last_activity < cutoff`. + // Without this index it's a full table scan that grows linearly with + // total sessions ever created. + lastActivityIdx: index("sessions_last_activity_idx").on(t.lastActivity), +}));