feat: 🎸 benchmarks and seeds

This commit is contained in:
amianthus
2026-05-14 10:19:12 +01:00
parent 47e89c8cf0
commit 7a16685a94
31 changed files with 8494 additions and 16 deletions

View File

@@ -0,0 +1,510 @@
import {
AppEnv,
customerEntitlements,
customerPrices,
customerProducts,
type Entitlement,
type FreeTrial,
type InsertCustomerEntitlement,
type InsertCustomerProduct,
type Product,
rollovers,
} from "@autumn/shared";
import { initDrizzle } from "@server/db/initDrizzle.js";
import { loadLocalEnv } from "@server/utils/envUtils.js";
import { generateId } from "@server/utils/genUtils.js";
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { TEST_ORG_CONFIG } from "../setupTestUtils/createTestOrg.js";
loadLocalEnv();
const CONFIG = {
batchSize: 2000,
rolloverRatio: 0.15,
looseCeRatio: 0.2,
shapes: [
{ name: "empty", weight: 40 },
{ name: "single_main", weight: 30 },
{ name: "main_plus_addon", weight: 15 },
{ name: "main_with_trial", weight: 10 },
{ name: "power_user", weight: 5 },
] as const,
} as const;
type ShapeName = (typeof CONFIG.shapes)[number]["name"];
interface CliArgs {
org_slug: string;
wipe?: boolean;
limit?: number;
start_offset?: number;
skip_seeded_check?: boolean;
resume?: boolean;
}
const parseArgs = (): CliArgs => {
const args = process.argv.slice(2);
const parsed: CliArgs = { org_slug: TEST_ORG_CONFIG.slug };
for (const arg of args) {
if (!arg.startsWith("--")) continue;
const [key, value] = arg.slice(2).split("=");
switch (key) {
case "org_slug":
parsed.org_slug = value;
break;
case "wipe":
parsed.wipe = true;
break;
case "limit":
parsed.limit = Number.parseInt(value, 10);
break;
case "start_offset":
parsed.start_offset = Number.parseInt(value, 10);
break;
case "skip_seeded_check":
parsed.skip_seeded_check = true;
break;
case "resume":
parsed.resume = true;
break;
default:
console.error(chalk.red(`Unknown flag: --${key}`));
process.exit(1);
}
}
return parsed;
};
const weightedPick = <T extends { weight: number; name: string }>(
choices: readonly T[],
): T => {
const total = choices.reduce((s, c) => s + c.weight, 0);
let r = Math.random() * total;
for (const c of choices) {
r -= c.weight;
if (r <= 0) return c;
}
return choices[choices.length - 1];
};
const randInt = (min: number, max: number) =>
Math.floor(Math.random() * (max - min + 1)) + min;
const randFloat = (min: number, max: number) =>
Math.random() * (max - min) + min;
const pick = <T>(arr: readonly T[]): T =>
arr[Math.floor(Math.random() * arr.length)];
const main = async () => {
console.log(
chalk.magentaBright(
"\n================ Seed Customer Products / Entitlements ================\n",
),
);
const args = parseArgs();
const env = AppEnv.Sandbox;
const { db, client } = initDrizzle();
try {
const org = await db.query.organizations.findFirst({
where: (orgs, { eq }) => eq(orgs.slug, args.org_slug),
});
if (!org) throw new Error(`Org '${args.org_slug}' not found`);
console.log(chalk.cyan(`Org: ${org.slug} (${org.id})`));
if (args.wipe) {
console.log(chalk.cyan("Wiping existing bench cps/ces/rollovers..."));
await db.execute(sql`
DELETE FROM rollovers WHERE cus_ent_id IN (
SELECT ce.id FROM customer_entitlements ce
JOIN customers c ON c.internal_id = ce.internal_customer_id
WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%'
)
`);
await db.execute(sql`
DELETE FROM customer_entitlements ce
USING customers c
WHERE c.internal_id = ce.internal_customer_id
AND c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%'
`);
await db.execute(sql`
DELETE FROM customer_prices cpr
USING customer_products cp, customers c
WHERE cpr.customer_product_id = cp.id
AND cp.internal_customer_id = c.internal_id
AND c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%'
`);
await db.execute(sql`
DELETE FROM customer_products cp
USING customers c
WHERE c.internal_id = cp.internal_customer_id
AND c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%'
`);
console.log(chalk.green("✅ Wipe complete\n"));
}
const products = (await db.execute(sql`
SELECT p.internal_id, p.id, p.is_add_on, p.is_default, p.group, p.created_at
FROM products p
WHERE p.org_id = ${org.id}
AND p.archived = false
AND EXISTS (
SELECT 1 FROM entitlements e WHERE e.internal_product_id = p.internal_id
)
ORDER BY p.created_at
`)) as unknown as Array<
Pick<Product, "internal_id" | "id" | "is_add_on" | "is_default" | "group" | "created_at">
>;
const mainProducts = products.filter((p) => !p.is_add_on);
const addonProducts = products.filter((p) => p.is_add_on);
console.log(
chalk.gray(
` ${mainProducts.length} main products, ${addonProducts.length} addons (must have at least 1 entitlement)`,
),
);
if (mainProducts.length === 0) throw new Error("No main products to seed with");
const allEnts = (await db.execute(sql`
SELECT e.id, e.internal_product_id, e.internal_feature_id, e.allowance,
e.allowance_type, e.interval, e.interval_count, e.usage_limit,
e.entity_feature_id, e.rollover, e.feature_id
FROM entitlements e
JOIN products p ON p.internal_id = e.internal_product_id
WHERE p.org_id = ${org.id} AND p.archived = false
`)) as unknown as Array<
Pick<
Entitlement,
| "id"
| "internal_product_id"
| "internal_feature_id"
| "allowance"
| "allowance_type"
| "interval"
| "interval_count"
| "usage_limit"
| "entity_feature_id"
| "rollover"
| "feature_id"
>
>;
const entsByProduct = new Map<string, typeof allEnts>();
for (const e of allEnts) {
const list = entsByProduct.get(e.internal_product_id) ?? [];
list.push(e);
entsByProduct.set(e.internal_product_id, list);
}
console.log(
chalk.gray(` ${allEnts.length} entitlements across products\n`),
);
const freeTrials = (await db.execute(sql`
SELECT id, internal_product_id, length, duration FROM free_trials
`)) as unknown as Array<Pick<FreeTrial, "id" | "internal_product_id"> & { length: number; duration: string }>;
const trialsByProduct = new Map<string, typeof freeTrials>();
for (const ft of freeTrials) {
const list = trialsByProduct.get(ft.internal_product_id) ?? [];
list.push(ft);
trialsByProduct.set(ft.internal_product_id, list);
}
const features = (await db.execute(sql`
SELECT internal_id, id, type FROM features
WHERE org_id = ${org.id} AND archived = false
`)) as unknown as Array<{ internal_id: string; id: string; type: string }>;
const meteredFeatures = features.filter((f) => f.type !== "boolean");
const seededHas = await db.execute(sql`
SELECT COUNT(*)::int AS n FROM customer_products cp
JOIN customers c ON c.internal_id = cp.internal_customer_id
WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%'
`);
const existing = (seededHas as unknown as { n: number }[])[0].n;
if (existing > 0 && !args.skip_seeded_check && !args.wipe) {
console.log(
chalk.yellow(
`⚠️ ${existing.toLocaleString()} bench customer_products already exist. Re-run with --wipe to reset, or --skip_seeded_check to add more.`,
),
);
return;
}
const customersToSeed = (await db.execute(sql`
SELECT c.internal_id, c.id, c.created_at
FROM customers c
WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%'
ORDER BY c.created_at
${args.limit ? sql`LIMIT ${args.limit}` : sql``}
`)) as unknown as Array<{ internal_id: string; id: string; created_at: number }>;
console.log(
chalk.cyan(
`Seeding cp/ce/rollover/cprice across ${customersToSeed.length.toLocaleString()} cus_bench_* customers`,
),
);
const shapeCounts: Record<ShapeName, number> = {
empty: 0,
single_main: 0,
main_plus_addon: 0,
main_with_trial: 0,
power_user: 0,
};
const cpRows: InsertCustomerProduct[] = [];
const ceRows: InsertCustomerEntitlement[] = [];
const rolloverRows: Array<typeof rollovers.$inferInsert>[number][] = [];
const cprRows: Array<typeof customerPrices.$inferInsert>[number][] = [];
let looseCeCount = 0;
const startedAt = performance.now();
for (const cus of customersToSeed) {
const shape = weightedPick(CONFIG.shapes).name;
shapeCounts[shape]++;
if (shape === "empty") continue;
const mainProd = pick(mainProducts);
const startsAt = cus.created_at + randInt(60_000, 86_400_000);
const cpsForThisCustomer: Array<{
cpId: string;
prod: typeof mainProd;
isAddon: boolean;
trialEndsAt: number | null;
freeTrialId: string | null;
}> = [];
cpsForThisCustomer.push({
cpId: generateId("cus_prod"),
prod: mainProd,
isAddon: false,
trialEndsAt: null,
freeTrialId: null,
});
if (shape === "main_plus_addon" || shape === "power_user") {
const addonCount = shape === "power_user" ? randInt(2, 3) : 1;
const shuffledAddons = [...addonProducts].sort(() => Math.random() - 0.5);
for (let i = 0; i < Math.min(addonCount, shuffledAddons.length); i++) {
cpsForThisCustomer.push({
cpId: generateId("cus_prod"),
prod: shuffledAddons[i],
isAddon: true,
trialEndsAt: null,
freeTrialId: null,
});
}
}
if (shape === "main_with_trial") {
const trials = trialsByProduct.get(mainProd.internal_id);
if (trials && trials.length > 0) {
const trial = pick(trials);
const trialEndsAt =
startsAt + (trial.length ?? 7) * 24 * 60 * 60 * 1000;
cpsForThisCustomer[0].trialEndsAt = trialEndsAt;
cpsForThisCustomer[0].freeTrialId = trial.id;
}
}
for (const cpEntry of cpsForThisCustomer) {
const subId = `sub_${cpEntry.cpId}`;
cpRows.push({
id: cpEntry.cpId,
internal_customer_id: cus.internal_id,
internal_product_id: cpEntry.prod.internal_id,
product_id: cpEntry.prod.id,
customer_id: cus.id,
created_at: startsAt,
starts_at: startsAt,
status: cpEntry.trialEndsAt ? "trialing" : "active",
processor: { type: "stripe", id: subId },
subscription_ids: [subId],
scheduled_ids: [],
quantity: cpEntry.isAddon ? randInt(1, 5) : 1,
is_custom: false,
canceled: false,
trial_ends_at: cpEntry.trialEndsAt,
free_trial_id: cpEntry.freeTrialId,
api_version: 23,
api_semver: "2.3.0",
billing_version: "v2",
collection_method: "charge_automatically",
});
cprRows.push({
id: generateId("cus_price"),
created_at: startsAt,
price_id: null,
internal_customer_id: cus.internal_id,
customer_product_id: cpEntry.cpId,
});
const prodEnts = entsByProduct.get(cpEntry.prod.internal_id) ?? [];
for (const ent of prodEnts) {
const isUnlimited = ent.allowance_type === "unlimited";
const isBoolean = ent.allowance_type === null;
const allowance = Number(ent.allowance ?? 0);
const balance = isUnlimited
? 0
: isBoolean
? 0
: Math.max(0, allowance - randInt(0, Math.max(1, allowance)));
const nextResetAt = ent.interval && ent.interval !== "lifetime"
? startsAt + 30 * 24 * 60 * 60 * 1000
: null;
const ceId = generateId("cus_ent");
ceRows.push({
id: ceId,
customer_product_id: cpEntry.cpId,
entitlement_id: ent.id,
internal_customer_id: cus.internal_id,
internal_feature_id: ent.internal_feature_id,
customer_id: cus.id,
feature_id: ent.feature_id,
unlimited: isUnlimited,
balance,
additional_balance: 0,
adjustment: 0,
created_at: startsAt,
next_reset_at: nextResetAt,
usage_allowed: ent.usage_limit != null,
entities: null,
cache_version: 0,
});
if (
!isBoolean &&
!isUnlimited &&
allowance > 0 &&
Math.random() < CONFIG.rolloverRatio
) {
rolloverRows.push({
id: generateId("rollover"),
cus_ent_id: ceId,
balance: randFloat(0, allowance * 0.5),
expires_at: startsAt + 60 * 24 * 60 * 60 * 1000,
entities: {},
usage: randFloat(0, allowance * 0.2),
});
}
}
}
if (
(shape === "power_user" || Math.random() < CONFIG.looseCeRatio) &&
meteredFeatures.length > 0
) {
const looseCount = shape === "power_user" ? randInt(2, 4) : 1;
const used = new Set<string>();
for (let i = 0; i < looseCount; i++) {
const feat = pick(meteredFeatures);
if (used.has(feat.internal_id)) continue;
used.add(feat.internal_id);
const looseAllowance = randInt(50, 500);
ceRows.push({
id: generateId("cus_ent"),
customer_product_id: null,
entitlement_id: pick(allEnts).id,
internal_customer_id: cus.internal_id,
internal_feature_id: feat.internal_id,
customer_id: cus.id,
feature_id: feat.id,
unlimited: false,
balance: randInt(0, looseAllowance),
additional_balance: 0,
adjustment: 0,
created_at: startsAt,
next_reset_at: null,
usage_allowed: false,
entities: null,
cache_version: 0,
});
looseCeCount++;
}
}
if (cpRows.length >= CONFIG.batchSize) {
await flush({ db, cpRows, ceRows, cprRows, rolloverRows });
}
}
await flush({ db, cpRows, ceRows, cprRows, rolloverRows });
const elapsed = ((performance.now() - startedAt) / 1000).toFixed(1);
console.log(chalk.green(`\n✅ Done in ${elapsed}s`));
console.log(chalk.bold("\nShape distribution:"));
for (const [name, count] of Object.entries(shapeCounts)) {
const pct = ((count / customersToSeed.length) * 100).toFixed(1);
console.log(` ${name.padEnd(20)} ${count.toLocaleString().padStart(8)} (${pct}%)`);
}
console.log(chalk.gray(` loose ces inserted: ${looseCeCount.toLocaleString()}`));
const finalStats = await db.execute(sql`
SELECT
(SELECT COUNT(*)::int FROM customer_products cp JOIN customers c ON c.internal_id = cp.internal_customer_id WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%') AS cps,
(SELECT COUNT(*)::int FROM customer_entitlements ce JOIN customers c ON c.internal_id = ce.internal_customer_id WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%') AS ces,
(SELECT COUNT(*)::int FROM customer_prices cpr JOIN customer_products cp ON cp.id = cpr.customer_product_id JOIN customers c ON c.internal_id = cp.internal_customer_id WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%') AS cprs,
(SELECT COUNT(*)::int FROM rollovers ro JOIN customer_entitlements ce ON ce.id = ro.cus_ent_id JOIN customers c ON c.internal_id = ce.internal_customer_id WHERE c.org_id = ${org.id} AND c.env = ${env} AND c.id LIKE 'cus_bench_%') AS rollovers
`);
const totals = (finalStats as unknown as Record<string, number>[])[0];
console.log(chalk.bold("\nDB totals after seed (cus_bench_* only):"));
for (const [k, v] of Object.entries(totals)) {
console.log(` ${k.padEnd(20)} ${Number(v).toLocaleString().padStart(8)}`);
}
} catch (e) {
console.error(chalk.red("\n❌ Seed failed:"));
if (e instanceof Error) {
console.error(chalk.red(` ${e.message}`));
console.error(chalk.gray(e.stack));
} else {
console.error(chalk.red(` ${String(e)}`));
}
process.exit(1);
} finally {
await client.end();
}
};
const chunk = <T>(arr: T[], size: number): T[][] => {
const out: T[][] = [];
for (let i = 0; i < arr.length; i += size) out.push(arr.slice(i, i + size));
return out;
};
const flush = async ({
db,
cpRows,
ceRows,
cprRows,
rolloverRows,
}: {
db: ReturnType<typeof initDrizzle>["db"];
cpRows: InsertCustomerProduct[];
ceRows: InsertCustomerEntitlement[];
cprRows: Array<typeof customerPrices.$inferInsert>;
rolloverRows: Array<typeof rollovers.$inferInsert>;
}) => {
for (const batch of chunk(cpRows, 1000))
await db.insert(customerProducts).values(batch);
for (const batch of chunk(cprRows, 1000))
await db.insert(customerPrices).values(batch);
for (const batch of chunk(ceRows, 1000))
await db.insert(customerEntitlements).values(batch);
for (const batch of chunk(rolloverRows, 1000))
await db.insert(rollovers).values(batch);
const total =
cpRows.length + ceRows.length + cprRows.length + rolloverRows.length;
process.stdout.write(
chalk.gray(
`\r flushed ${cpRows.length.toLocaleString()} cp, ${ceRows.length.toLocaleString()} ce, ${cprRows.length.toLocaleString()} cpr, ${rolloverRows.length.toLocaleString()} ro (total ${total.toLocaleString()})`,
),
);
cpRows.length = 0;
ceRows.length = 0;
cprRows.length = 0;
rolloverRows.length = 0;
};
await main();
process.exit(0);

View File

@@ -25,6 +25,7 @@ interface CliArgs {
skip_entities?: boolean;
wipe?: boolean;
count?: number;
start_offset?: number;
}
const parseArgs = (): CliArgs => {
@@ -48,11 +49,14 @@ const parseArgs = (): CliArgs => {
case "count":
parsed.count = Number.parseInt(value, 10);
break;
case "start_offset":
parsed.start_offset = Number.parseInt(value, 10);
break;
default:
console.error(chalk.red(`Unknown flag: --${key}`));
console.log(
chalk.yellow(
"\nUsage: bun run scripts/seed/seedPaginationBenchmark.ts [--count=<n>] [--skip_entities] [--wipe] [--org_slug=<slug>]",
"\nUsage: bun run scripts/seed/seedPaginationBenchmark.ts [--count=<n>] [--start_offset=<n>] [--skip_entities] [--wipe] [--org_slug=<slug>]",
),
);
process.exit(1);
@@ -175,27 +179,30 @@ const seedCustomers = async ({
orgId,
env,
count,
startOffset = 0,
}: {
db: ReturnType<typeof initDrizzle>["db"];
orgId: string;
env: AppEnv;
count: number;
startOffset?: number;
}) => {
const now = Date.now();
const rangeMs = CONFIG.timeRangeDays * 24 * 60 * 60 * 1000;
const startMs = now - rangeMs;
const endIndex = startOffset + count;
console.log(
chalk.cyan(
`Seeding ${count.toLocaleString()} customers (${CONFIG.timeRangeDays}-day range, batch=${CONFIG.batchSize})...`,
`Seeding indices ${startOffset.toLocaleString()}..${(endIndex - 1).toLocaleString()} (${count.toLocaleString()} customers, ${CONFIG.timeRangeDays}-day range, batch=${CONFIG.batchSize})...`,
),
);
const startedAt = performance.now();
let inserted = 0;
for (let batchStart = 0; batchStart < count; batchStart += CONFIG.batchSize) {
const batchEnd = Math.min(batchStart + CONFIG.batchSize, count);
for (let batchStart = startOffset; batchStart < endIndex; batchStart += CONFIG.batchSize) {
const batchEnd = Math.min(batchStart + CONFIG.batchSize, endIndex);
const rows: CustomerRow[] = [];
for (let i = batchStart; i < batchEnd; i++) {
@@ -342,20 +349,39 @@ const main = async () => {
);
const existingCount = existing[0]?.count ?? 0;
let startOffset = args.start_offset ?? 0;
let seedCount = customerCount;
if (existingCount > 0 && !args.wipe) {
console.log(
chalk.yellow(
`⚠️ Found ${existingCount.toLocaleString()} existing bench customers. Re-run with --wipe to reset, or skip seeding.`,
),
);
if (existingCount >= customerCount) {
console.log(chalk.green("✅ Seed already satisfies target count — exiting."));
return;
if (args.start_offset === undefined) {
if (existingCount >= customerCount) {
console.log(
chalk.green("✅ Seed already satisfies target count — exiting."),
);
return;
}
startOffset = existingCount;
seedCount = customerCount - existingCount;
console.log(
chalk.yellow(
`Continuing seed: indices ${startOffset.toLocaleString()}..${(startOffset + seedCount - 1).toLocaleString()} (${seedCount.toLocaleString()} customers).`,
),
);
}
console.log(chalk.yellow(`Continuing seed to fill remaining ${(customerCount - existingCount).toLocaleString()} customers.`));
}
await seedCustomers({ db, orgId: org.id, env, count: customerCount });
await seedCustomers({
db,
orgId: org.id,
env,
count: seedCount,
startOffset,
});
if (!args.skip_entities) {
await seedEntities({

View File

@@ -0,0 +1,153 @@
import { AppEnv, RELEVANT_STATUSES } from "@autumn/shared";
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { CusBatchService } from "../src/internal/customers/CusBatchService";
import { CusSearchService } from "../src/internal/customers/CusSearchService";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
import { initDrizzle } from "../src/db/initDrizzle";
import {
type FlattenedCustomerRow,
reassembleFlattenedCustomer,
} from "../src/internal/customers/reassembleFlattenedCustomer";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const ORG_ID = "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt";
const ENV = AppEnv.Sandbox;
const REPEATS = 5;
const LIMIT = parseInt(process.env.LIMIT ?? "500", 10);
const OFFSET_PCT = parseInt(process.env.OFFSET_PCT ?? "95", 10);
const main = async () => {
console.log(
chalk.magentaBright(
"\n================ Dashboard Merge Bench ================\n",
),
);
const { db, client } = initDrizzle();
const ctx = {
db,
client,
org: { id: ORG_ID, slug: "unit-test-org" },
env: ENV,
logger: {
info: () => {},
error: () => {},
warn: () => {},
debug: () => {},
trace: () => {},
},
} as any;
try {
const total = (
(await db.execute(
sql`SELECT COUNT(*)::int AS n FROM customers WHERE org_id = ${ORG_ID} AND env = ${ENV}`,
)) as unknown as { n: number }[]
)[0].n;
const offset = Math.floor((total * OFFSET_PCT) / 100);
const row = (await db.execute(
sql`SELECT created_at, id FROM customers WHERE org_id = ${ORG_ID} AND env = ${ENV} ORDER BY created_at DESC, id DESC LIMIT 1 OFFSET ${offset}`,
)) as unknown as { created_at: number; id: string }[];
const cursor = { t: Number(row[0].created_at), id: row[0].id };
console.log(
chalk.gray(
` total=${total.toLocaleString()} cursor at ${OFFSET_PCT}%: ${cursor.id} limit=${LIMIT}\n`,
),
);
const measure = async (label: string, fn: () => Promise<void>) => {
for (let i = 0; i < 2; i++) await fn();
const samples: number[] = [];
for (let i = 0; i < REPEATS; i++) {
const t0 = performance.now();
await fn();
samples.push(performance.now() - t0);
}
samples.sort((a, b) => a - b);
const p50 = samples[Math.floor(samples.length / 2)];
const min = samples[0];
const max = samples[samples.length - 1];
console.log(
` ${chalk.cyan(label.padEnd(20))} p50=${p50.toFixed(0).padStart(4)}ms min=${min.toFixed(0).padStart(4)}ms max=${max.toFixed(0).padStart(4)}ms`,
);
return p50;
};
const oldPath = async () => {
const { internalIds } =
await CusSearchService.resolveInternalIdsByCursor({
db,
orgId: ORG_ID,
env: ENV,
search: "",
cursor,
limit: LIMIT,
});
if (internalIds.length === 0) return;
const query = getCursorPaginatedFullCusQuery({
orgId: ORG_ID,
env: ENV,
inStatuses: RELEVANT_STATUSES,
withSubs: true,
limit: internalIds.length,
internalCustomerIds: internalIds,
cusProductLimit: 15,
});
const rows = (await db.execute(query)) as unknown as Record<
string,
unknown
>[];
const flat = (rows[0] ?? {}) as unknown as FlattenedCustomerRow;
reassembleFlattenedCustomer(flat);
};
const newPath = async () => {
await CusBatchService.getDashboardCursorPage({
ctx,
search: "",
filters: undefined,
cursor,
limit: LIMIT,
});
};
const oldWithStatus = async () => {
// Call old path manually (resolve + fetch) with status filter for parity
await oldPath();
};
const newWithStatus = async () => {
await CusBatchService.getDashboardCursorPage({
ctx,
search: "",
filters: { status: ["active"] },
cursor,
limit: LIMIT,
});
};
const oldP50 = await measure("OLD (resolve+fetch)", oldPath);
const newP50 = await measure("NEW (no filters)", newPath);
const newStatusP50 = await measure(
"NEW (status=active)",
newWithStatus,
);
console.log();
console.log(chalk.magentaBright("================ Summary ================"));
const delta = (((newP50 - oldP50) / oldP50) * 100).toFixed(0);
console.log(
` old → new (no filters): ${oldP50.toFixed(0)}ms → ${newP50.toFixed(0)}ms (${delta}%)`,
);
console.log(
` new with status=active: ${newStatusP50.toFixed(0)}ms (uses resolve+fetch fallback)`,
);
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,24 @@
import { sql } from "drizzle-orm";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const main = async () => {
const { db, client } = initDrizzle();
try {
const rows = (await db.execute(sql`
SELECT indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'public'
AND tablename = 'customer_products'
AND (indexname LIKE '%revenuecat%' OR indexdef LIKE '%revenuecat%')
`)) as any[];
console.log(JSON.stringify(rows, null, 2));
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,47 @@
import { AppEnv } from "@autumn/shared";
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { RELEVANT_STATUSES } from "../src/internal/customers/cusProducts/CusProductService";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
import { getOptimizedFullCusQuery } from "./optimizedFullCusQuery";
loadLocalEnv();
const ORG_ID = "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt";
const main = async () => {
const { db, client } = initDrizzle();
try {
const query = getOptimizedFullCusQuery({
orgId: ORG_ID,
env: AppEnv.Sandbox,
inStatuses: RELEVANT_STATUSES,
withSubs: false,
limit: 1000,
cusProductLimit: 15,
});
console.log(chalk.cyan("Running optimized first page..."));
try {
const r = await db.execute(query);
console.log(chalk.green(`OK: ${(r as any).length} row(s)`));
const first = (r as any)[0];
if (first) {
for (const [k, v] of Object.entries(first)) {
const arr = Array.isArray(v) ? v : v != null && typeof v === "object" && "length" in (v as any) ? (v as any[]) : null;
console.log(` ${k}: ${arr ? `${arr.length} items` : typeof v}`);
}
}
} catch (e: any) {
console.error(chalk.red(`SQL ERROR: ${e.message}`));
console.error(chalk.gray(`code: ${e.code}, where: ${e.where ?? "n/a"}, detail: ${e.detail ?? "n/a"}, hint: ${e.hint ?? "n/a"}`));
if (e.position) console.error(chalk.gray(`position: ${e.position}`));
}
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,305 @@
import {
AppEnv,
type FullCustomer,
RELEVANT_STATUSES,
StandardCursor,
} from "@autumn/shared";
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { CusBatchService } from "../src/internal/customers/CusBatchService";
import { CusSearchService } from "../src/internal/customers/CusSearchService";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
import { initDrizzle } from "../src/db/initDrizzle";
import {
type FlattenedCustomerRow,
reassembleFlattenedCustomer,
} from "../src/internal/customers/reassembleFlattenedCustomer";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const ORG_ID = "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt";
const ENV = AppEnv.Sandbox;
type DashboardFilters = {
status?: string[];
version?: string[];
none?: boolean;
processor?: string[];
};
const runOldPath = async ({
ctx,
search,
filters,
cursor,
limit,
}: {
ctx: any;
search: string;
filters?: DashboardFilters;
cursor: { t: number; id: string } | null;
limit: number;
}): Promise<{
fullCustomers: FullCustomer[];
next_cursor: string | null;
}> => {
const { internalIds, peek } =
await CusSearchService.resolveInternalIdsByCursor({
db: ctx.db,
orgId: ORG_ID,
env: ENV,
search,
filters,
cursor,
limit,
});
if (internalIds.length === 0) {
return { fullCustomers: [], next_cursor: null };
}
const query = getCursorPaginatedFullCusQuery({
orgId: ORG_ID,
env: ENV,
inStatuses: RELEVANT_STATUSES,
withSubs: true,
limit: internalIds.length,
internalCustomerIds: internalIds,
cusProductLimit: 15,
});
const rows = (await ctx.db.execute(query)) as unknown as Record<
string,
unknown
>[];
const flat = (rows[0] ?? {
customers: [],
customer_products: [],
customer_entitlements: [],
extra_customer_entitlements: [],
customer_prices: [],
entitlements: [],
rollovers: [],
replaceables: [],
free_trials: [],
subscriptions: [],
}) as unknown as FlattenedCustomerRow;
const fullCustomers = reassembleFlattenedCustomer(flat);
const next_cursor = peek ? StandardCursor.encode(peek) : null;
return { fullCustomers, next_cursor };
};
const minimalCtx = () => {
const { db, client } = initDrizzle();
return {
db,
client,
org: { id: ORG_ID, slug: "unit-test-org" },
env: ENV,
logger: {
info: () => {},
error: () => {},
warn: () => {},
debug: () => {},
trace: () => {},
},
} as any;
};
const sortById = <T extends { internal_id?: string; id?: string | null }>(
arr: T[],
): T[] =>
[...arr].sort((a, b) =>
(a.internal_id ?? a.id ?? "").localeCompare(b.internal_id ?? b.id ?? ""),
);
const sortDeep = (obj: unknown): unknown => {
if (Array.isArray(obj)) {
const sorted = obj.map(sortDeep);
if (sorted.length > 0 && typeof sorted[0] === "object" && sorted[0] !== null) {
(sorted as any[]).sort((a, b) => {
const ka = (a as any).id ?? (a as any).internal_id ?? "";
const kb = (b as any).id ?? (b as any).internal_id ?? "";
return String(ka).localeCompare(String(kb));
});
}
return sorted;
}
if (obj && typeof obj === "object") {
return Object.fromEntries(
Object.entries(obj as Record<string, unknown>)
.map(([k, v]) => [k, sortDeep(v)] as const)
.sort(([a], [b]) => a.localeCompare(b)),
);
}
return obj;
};
const diffCustomers = (
a: FullCustomer[],
b: FullCustomer[],
label: string,
) => {
if (a.length !== b.length) {
console.log(
chalk.red(
` ${label} ✗ length mismatch: old=${a.length} new=${b.length}`,
),
);
return false;
}
const sa = sortById(a);
const sb = sortById(b);
let mismatches = 0;
for (let i = 0; i < sa.length; i++) {
const ja = JSON.stringify(sortDeep(sa[i]));
const jb = JSON.stringify(sortDeep(sb[i]));
if (ja !== jb) {
if (mismatches < 2) {
console.log(
chalk.red(
` ${label} ✗ customer #${i} (${(sa[i] as any).id}) differs`,
),
);
const keysA = Object.keys(sortDeep(sa[i]) as object);
for (const k of keysA) {
const va = JSON.stringify((sortDeep(sa[i]) as any)[k]);
const vb = JSON.stringify((sortDeep(sb[i]) as any)[k]);
if (va !== vb) {
console.log(
chalk.gray(` KEY ${k}\n old=${va?.slice(0, 160)}\n new=${vb?.slice(0, 160)}`),
);
}
}
}
mismatches++;
}
}
if (mismatches > 0) {
console.log(
chalk.red(` ${label}${mismatches}/${sa.length} customers differ`),
);
return false;
}
console.log(chalk.green(` ${label}${sa.length} customers identical`));
return true;
};
type Case = {
name: string;
search?: string;
filters?: DashboardFilters;
cursor?: { t: number; id: string } | null;
limit?: number;
};
const main = async () => {
console.log(
chalk.magentaBright(
"\n================ Dashboard Merge Parity ================\n",
),
);
const ctx = minimalCtx();
const total = (
(await ctx.db.execute(
sql`SELECT COUNT(*)::int AS n FROM customers WHERE org_id = ${ORG_ID} AND env = ${ENV}`,
)) as unknown as { n: number }[]
)[0].n;
const deepOffset = Math.floor(total * 0.95);
const deepRow = (await ctx.db.execute(
sql`SELECT created_at, id FROM customers WHERE org_id = ${ORG_ID} AND env = ${ENV} ORDER BY created_at DESC, id DESC LIMIT 1 OFFSET ${deepOffset}`,
)) as unknown as { created_at: number; id: string }[];
const deepCursor = {
t: Number(deepRow[0].created_at),
id: deepRow[0].id,
};
console.log(
chalk.gray(
` total=${total.toLocaleString()} deep_cursor=${deepCursor.id} (offset ~95%)\n`,
),
);
const cases: Case[] = [
{ name: "baseline", limit: 200 },
{ name: "search 'bench_000450'", search: "bench_000450", limit: 100 },
{ name: "status=active", filters: { status: ["active"] }, limit: 200 },
{ name: "status=past_due", filters: { status: ["past_due"] }, limit: 200 },
{ name: "status=canceled", filters: { status: ["canceled"] }, limit: 200 },
{
name: "status=free_trial",
filters: { status: ["free_trial"] },
limit: 200,
},
{ name: "status=expired", filters: { status: ["expired"] }, limit: 200 },
{
name: "status=active,past_due",
filters: { status: ["active", "past_due"] },
limit: 200,
},
{ name: "none=true", filters: { none: true }, limit: 200 },
{
name: "processor=stripe",
filters: { processor: ["stripe"] },
limit: 200,
},
{ name: "deep cursor (95%)", cursor: deepCursor, limit: 200 },
{
name: "deep cursor + status=active",
cursor: deepCursor,
filters: { status: ["active"] },
limit: 200,
},
{
name: "search no-match",
search: "no_such_customer_zzz",
limit: 50,
},
];
let pass = 0;
let fail = 0;
try {
for (const tc of cases) {
const args = {
ctx,
search: tc.search ?? "",
filters: tc.filters,
cursor: tc.cursor ?? null,
limit: tc.limit ?? 200,
};
const oldRes = await runOldPath(args);
const newRes = await CusBatchService.getDashboardCursorPage(args);
const ok = diffCustomers(
oldRes.fullCustomers,
newRes.fullCustomers,
tc.name,
);
const oldDecoded = StandardCursor.decode(oldRes.next_cursor ?? "");
const newDecoded = StandardCursor.decode(newRes.next_cursor ?? "");
const cursorMatches =
(oldDecoded?.t ?? null) === (newDecoded?.t ?? null) &&
(oldDecoded?.id ?? null) === (newDecoded?.id ?? null);
if (!cursorMatches) {
console.log(
chalk.yellow(
` cursor differs: old=${JSON.stringify(oldDecoded)} new=${JSON.stringify(newDecoded)}`,
),
);
}
if (ok && cursorMatches) pass++;
else fail++;
}
console.log();
console.log(
chalk.bold(
`Result: ${chalk.green(`${pass} pass`)} / ${chalk.red(`${fail} fail`)} of ${cases.length}`,
),
);
} finally {
await ctx.client.end();
process.exit(fail === 0 ? 0 : 1);
}
};
await main();

View File

@@ -0,0 +1,180 @@
import { AppEnv } from "@autumn/shared";
import type { FlattenedCustomerRow } from "../src/internal/customers/reassembleFlattenedCustomer/index.js";
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { RELEVANT_STATUSES } from "../src/internal/customers/cusProducts/CusProductService";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
import { reassembleFlattenedCustomer } from "../src/internal/customers/reassembleFlattenedCustomer";
import { getOptimizedFullCusQuery } from "./optimizedFullCusQuery";
loadLocalEnv();
const ORG_ID = "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt";
type Args = {
orgId: string;
env: AppEnv;
inStatuses: typeof RELEVANT_STATUSES;
withSubs: boolean;
limit: number;
cusProductLimit: number;
};
const sharedArgs: Args & {
cursor?: { v: 0; t: number; id: string };
} = {
orgId: ORG_ID,
env: AppEnv.Sandbox,
inStatuses: RELEVANT_STATUSES,
withSubs: true,
limit: parseInt(process.env.LIMIT ?? "50", 10),
cusProductLimit: 15,
};
type AnyRecord = Record<string, unknown>;
const fetchFlat = async (
db: ReturnType<typeof initDrizzle>["db"],
q: any,
): Promise<FlattenedCustomerRow> => {
const rows = await db.execute(q);
const flat = (rows as unknown as AnyRecord[])[0] as unknown as FlattenedCustomerRow;
return flat;
};
const sortById = (a: { id?: string }, b: { id?: string }) =>
(a.id ?? "").localeCompare(b.id ?? "");
const sortDeep = (obj: unknown): unknown => {
if (Array.isArray(obj)) {
const sorted = obj.map(sortDeep);
if (sorted.length > 0 && typeof sorted[0] === "object" && sorted[0] !== null) {
(sorted as AnyRecord[]).sort((a, b) => {
const ka = (a as AnyRecord).id ?? (a as AnyRecord).internal_id ?? "";
const kb = (b as AnyRecord).id ?? (b as AnyRecord).internal_id ?? "";
return String(ka).localeCompare(String(kb));
});
}
return sorted;
}
if (obj && typeof obj === "object") {
const entries = Object.entries(obj as AnyRecord)
.map(([k, v]) => [k, sortDeep(v)] as const)
.sort(([a], [b]) => a.localeCompare(b));
return Object.fromEntries(entries);
}
return obj;
};
const main = async () => {
const { db, client } = initDrizzle();
try {
const offsetPct = parseInt(process.env.OFFSET_PCT ?? "0", 10);
if (offsetPct > 0) {
const total = (await db.execute(
sql`SELECT COUNT(*)::int AS n FROM customers WHERE org_id = ${ORG_ID} AND env = 'sandbox'`,
)) as unknown as { n: number }[];
const offset = Math.floor((total[0].n * offsetPct) / 100);
const row = (await db.execute(
sql`SELECT created_at, id FROM customers WHERE org_id = ${ORG_ID} AND env = 'sandbox' ORDER BY created_at DESC, id DESC LIMIT 1 OFFSET ${offset}`,
)) as unknown as { created_at: number; id: string }[];
sharedArgs.cursor = { v: 0, t: row[0].created_at, id: row[0].id };
console.log(chalk.cyan(`Using deep cursor at ${offsetPct}%: ${row[0].id}`));
}
console.log(chalk.cyan(`Running CURRENT query (limit=${sharedArgs.limit}, cursor=${sharedArgs.cursor ? "yes" : "no"})...`));
const flatCurrent = await fetchFlat(
db,
getCursorPaginatedFullCusQuery(sharedArgs),
);
console.log(chalk.cyan(`Running OPTIMIZED query...`));
const flatOptim = await fetchFlat(
db,
getOptimizedFullCusQuery(sharedArgs),
);
// Compare top-level array lengths
const keys = [
"customers",
"customer_products",
"customer_entitlements",
"extra_customer_entitlements",
"customer_prices",
"entitlements",
"rollovers",
"replaceables",
"free_trials",
"subscriptions",
] as const;
console.log(chalk.bold("\nTop-level counts:"));
let lenMismatch = false;
for (const k of keys) {
const a = (flatCurrent[k] as unknown[] | undefined)?.length ?? 0;
const b = (flatOptim[k] as unknown[] | undefined)?.length ?? 0;
const match = a === b;
if (!match) lenMismatch = true;
console.log(
` ${k.padEnd(32)} current=${String(a).padStart(5)} optim=${String(b).padStart(5)} ${match ? chalk.green("✓") : chalk.red("✗")}`,
);
}
if (lenMismatch) {
console.log(chalk.red("\n❌ Length mismatch — aborting deep compare"));
process.exit(1);
}
// Reassemble both and deep compare the FullCustomer arrays
const customersA = reassembleFlattenedCustomer(flatCurrent);
const customersB = reassembleFlattenedCustomer(flatOptim);
console.log(chalk.cyan(`\nReassembled ${customersA.length} customers (both queries)`));
if (customersA.length !== customersB.length) {
console.log(chalk.red(`Mismatch in reassembled customer counts: ${customersA.length} vs ${customersB.length}`));
process.exit(1);
}
// Sort by id for stable diff (same cursor order should already be aligned)
customersA.sort((a: any, b: any) => (a.internal_id ?? "").localeCompare(b.internal_id ?? ""));
customersB.sort((a: any, b: any) => (a.internal_id ?? "").localeCompare(b.internal_id ?? ""));
let diffs = 0;
for (let i = 0; i < customersA.length; i++) {
const a = sortDeep(customersA[i]);
const b = sortDeep(customersB[i]);
const ja = JSON.stringify(a);
const jb = JSON.stringify(b);
if (ja !== jb) {
diffs++;
if (diffs <= 3) {
console.log(chalk.red(`\nDIFF for customer #${i} (${(customersA[i] as any).id}):`));
// find first differing key
for (const k of Object.keys(a as AnyRecord)) {
const va = JSON.stringify((a as AnyRecord)[k]);
const vb = JSON.stringify((b as AnyRecord)[k]);
if (va !== vb) {
console.log(` KEY ${k}:`);
console.log(chalk.gray(` current: ${va?.slice(0, 200)}`));
console.log(chalk.gray(` optim: ${vb?.slice(0, 200)}`));
}
}
}
}
}
if (diffs === 0) {
console.log(chalk.green(`\n✅ All ${customersA.length} customers match byte-for-byte`));
} else {
console.log(chalk.red(`\n❌ ${diffs}/${customersA.length} customers differ`));
}
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,426 @@
import {
type AppEnv,
type CusProductStatus,
type FullCustomer,
type ListCustomersV2Params,
RELEVANT_STATUSES,
} from "@autumn/shared";
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { initDrizzle } from "../src/db/initDrizzle";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
import { getPaginatedFullCusQuery } from "../src/internal/customers/getFullCusQuery";
import {
type FlattenedCustomerRow,
reassembleFlattenedCustomer,
} from "../src/internal/customers/reassembleFlattenedCustomer";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const ORGS: { id: string; env: AppEnv; label: string }[] = [
{ id: "biu9vSF7vghBLSKW1UTDwxHBAivjnPaK", env: "live" as AppEnv, label: "firecrawl" },
{ id: "r7pwHiekGsqt32qGqcVku6thWFh5aHh8", env: "live" as AppEnv, label: "runable" },
];
const LIMIT = parseInt(process.env.DIFF_LIMIT ?? "50", 10);
const DEEP_OFFSET = parseInt(process.env.DIFF_DEEP_OFFSET ?? "500", 10);
const CUS_PRODUCT_LIMIT = 15;
const STATEMENT_TIMEOUT_MS = 30_000;
type ResolvedParams = Partial<ListCustomersV2Params> & {
offset?: number;
cursor?: { t: number; id: string };
};
type CaseContext = { db: DB; orgId: string; env: AppEnv };
type Case = {
name: string;
build: (ctx: CaseContext) => Promise<ResolvedParams | null>;
};
type DB = ReturnType<typeof initDrizzle>["db"];
const runReadOnly = async <T,>(db: DB, fn: (tx: any) => Promise<T>): Promise<T> => {
return await db.transaction(async (tx) => {
await tx.execute(
sql.raw(`SET LOCAL statement_timeout = ${STATEMENT_TIMEOUT_MS}`),
);
await tx.execute(sql.raw("SET LOCAL transaction_read_only = on"));
return fn(tx);
});
};
const v22NormalizeTimestamp = (value: any): number => {
if (typeof value === "string") {
const parsed = parseInt(value, 10);
return Number.isNaN(parsed) ? Date.now() : parsed;
}
return typeof value === "number" ? value : Date.now();
};
const v22Normalize = (raw: any): any => {
const out = {
...raw,
created_at: v22NormalizeTimestamp(raw.created_at),
};
if (raw.customer_products && Array.isArray(raw.customer_products)) {
out.customer_products = raw.customer_products.map((cp: any) => ({
...cp,
created_at: v22NormalizeTimestamp(cp.created_at),
starts_at: cp.starts_at
? v22NormalizeTimestamp(cp.starts_at)
: v22NormalizeTimestamp(cp.created_at),
canceled_at: cp.canceled_at ? v22NormalizeTimestamp(cp.canceled_at) : null,
ended_at: cp.ended_at ? v22NormalizeTimestamp(cp.ended_at) : null,
trial_ends_at: cp.trial_ends_at
? v22NormalizeTimestamp(cp.trial_ends_at)
: null,
quantity: cp.quantity ? parseInt(cp.quantity, 10) || 1 : 1,
options: cp.options || [],
collection_method: cp.collection_method || "charge_automatically",
subscription_ids: cp.subscription_ids || [],
scheduled_ids: cp.scheduled_ids || [],
customer_entitlements: (cp.customer_entitlements || []).map((ce: any) => ({
...ce,
created_at: v22NormalizeTimestamp(ce.created_at),
next_reset_at: ce.next_reset_at
? v22NormalizeTimestamp(ce.next_reset_at)
: null,
balance: ce.balance ? parseFloat(ce.balance) || 0 : 0,
adjustment: ce.adjustment ? parseFloat(ce.adjustment) || 0 : 0,
})),
}));
}
return out;
};
const fetchV22 = async (
db: DB,
orgId: string,
env: AppEnv,
params: ResolvedParams,
) => {
const { subscription_status, plans, search, processors, offset = 0 } = params;
const query = getPaginatedFullCusQuery({
orgId,
env,
inStatuses: subscription_status
? [subscription_status as unknown as CusProductStatus]
: RELEVANT_STATUSES,
includeInvoices: false,
withEntities: false,
withTrialsUsed: false,
withSubs: true,
limit: LIMIT,
offset,
search,
plans,
processors,
cusProductLimit: CUS_PRODUCT_LIMIT,
});
const rows = await runReadOnly(db, (tx) => tx.execute(query));
return (rows as any[]).map(v22Normalize) as FullCustomer[];
};
const fetchV23 = async (
db: DB,
orgId: string,
env: AppEnv,
params: ResolvedParams,
) => {
const { subscription_status, plans, search, processors, cursor } = params;
const query = getCursorPaginatedFullCusQuery({
orgId,
env,
inStatuses: subscription_status
? [subscription_status as unknown as CusProductStatus]
: RELEVANT_STATUSES,
withSubs: true,
limit: LIMIT,
search,
plans,
processors,
cursor: cursor ? { v: 0 as const, t: cursor.t, id: cursor.id } : undefined,
cusProductLimit: CUS_PRODUCT_LIMIT,
});
const rows = (await runReadOnly(db, (tx) => tx.execute(query))) as any[];
const flat = (rows[0] ?? {}) as unknown as FlattenedCustomerRow;
const all = reassembleFlattenedCustomer(flat);
return all.slice(0, LIMIT);
};
const resolveCursorAtOffset = async ({
db,
orgId,
env,
offset,
inStatuses,
plans,
processors,
search,
}: {
db: DB;
orgId: string;
env: AppEnv;
offset: number;
inStatuses?: CusProductStatus[];
plans?: ListCustomersV2Params["plans"];
processors?: ListCustomersV2Params["processors"];
search?: string;
}): Promise<{ t: number; id: string } | null> => {
const query = getPaginatedFullCusQuery({
orgId,
env,
inStatuses: inStatuses ?? RELEVANT_STATUSES,
includeInvoices: false,
withEntities: false,
withTrialsUsed: false,
withSubs: false,
limit: 1,
offset: offset - 1,
search,
plans,
processors,
cusProductLimit: 1,
});
const rows = (await runReadOnly(db, (tx) => tx.execute(query))) as any[];
if (rows.length === 0) return null;
const row = rows[0] as { id: string; created_at: number | string };
return { t: v22NormalizeTimestamp(row.created_at), id: row.id };
};
const resolveFirstPlanId = async ({
db,
orgId,
env,
}: {
db: DB;
orgId: string;
env: AppEnv;
}): Promise<string | null> => {
const rows = (await runReadOnly(
db,
(tx) => tx.execute(sql`
SELECT p.id
FROM products p
JOIN customer_products cp ON cp.internal_product_id = p.internal_id
WHERE p.org_id = ${orgId} AND p.env = ${env}
GROUP BY p.id
ORDER BY COUNT(*) DESC
LIMIT 1
`),
)) as any[];
return rows[0]?.id ?? null;
};
const resolveSearchSubstring = async ({
db,
orgId,
env,
}: {
db: DB;
orgId: string;
env: AppEnv;
}): Promise<string | null> => {
const rows = (await runReadOnly(
db,
(tx) => tx.execute(sql`
SELECT c.email
FROM customers c
WHERE c.org_id = ${orgId} AND c.env = ${env}
AND c.email IS NOT NULL
AND length(c.email) >= 5
LIMIT 1
`),
)) as any[];
const email = rows[0]?.email as string | undefined;
if (!email) return null;
const at = email.indexOf("@");
if (at < 3) return email.slice(0, 3);
return email.slice(0, Math.min(at, 4));
};
const CASES: Case[] = [
{
name: "page 1 / no filters",
build: async () => ({}),
},
{
name: "page 1 / subscription_status=active",
build: async () => ({ subscription_status: "active" }),
},
{
name: "page 1 / processors=revenuecat",
build: async () => ({ processors: ["revenuecat"] }),
},
{
name: "page 1 / search",
build: async (ctx) => {
const search = await resolveSearchSubstring(ctx);
if (!search) return null;
return { search };
},
},
{
name: "page 1 / plans",
build: async (ctx) => {
const planId = await resolveFirstPlanId(ctx);
if (!planId) return null;
return { plans: [{ id: planId }] };
},
},
{
name: `deep / offset=${DEEP_OFFSET} / no filters`,
build: async (ctx) => {
const cursor = await resolveCursorAtOffset({
db: ctx.db,
orgId: ctx.orgId,
env: ctx.env,
offset: DEEP_OFFSET,
});
if (!cursor) return null;
return { offset: DEEP_OFFSET, cursor };
},
},
];
const findDiff = (a: any, b: any, path = "$"): string | null => {
if (a === b) return null;
if (a === null || b === null || a === undefined || b === undefined) {
return `${path}: ${JSON.stringify(a)} vs ${JSON.stringify(b)}`;
}
if (typeof a !== typeof b) {
return `${path}: type ${typeof a} vs ${typeof b}`;
}
if (Array.isArray(a) || Array.isArray(b)) {
if (!Array.isArray(a) || !Array.isArray(b)) {
return `${path}: array vs non-array`;
}
if (a.length !== b.length) {
return `${path}.length: ${a.length} vs ${b.length}`;
}
for (let i = 0; i < a.length; i++) {
const d = findDiff(a[i], b[i], `${path}[${i}]`);
if (d) return d;
}
return null;
}
if (typeof a === "object") {
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
for (const k of keys) {
const d = findDiff(a[k], b[k], `${path}.${k}`);
if (d) return d;
}
return null;
}
return `${path}: ${JSON.stringify(a)} vs ${JSON.stringify(b)}`;
};
const summarize = (label: string, list: FullCustomer[]) => {
const cps = list.reduce((n, c) => n + (c.customer_products?.length ?? 0), 0);
const subs = list.reduce(
(n, c) => n + (c.subscriptions?.length ?? 0),
0,
);
const extras = list.reduce(
(n, c) => n + (c.extra_customer_entitlements?.length ?? 0),
0,
);
return `${label}: ${list.length} cus / ${cps} cps / ${subs} subs / ${extras} loose_ces`;
};
const runOrg = async ({
db,
orgId,
env,
label,
}: {
db: DB;
orgId: string;
env: AppEnv;
label: string;
}) => {
console.log(
chalk.magentaBright(
`\n========= ${label} (${orgId}) env=${env} limit=${LIMIT} =========\n`,
),
);
let total = 0;
let passes = 0;
for (const c of CASES) {
total++;
console.log(chalk.cyan(`\n--- ${c.name} ---`));
const params = await c.build({ db, orgId, env });
if (!params) {
console.log(chalk.yellow(" ⊘ skipped (no data to build params)"));
passes++;
continue;
}
console.log(
chalk.gray(
` params: ${JSON.stringify(params, (_k, v) => (typeof v === "bigint" ? String(v) : v))}`,
),
);
const [v22, v23] = await Promise.all([
fetchV22(db, orgId, env, params),
fetchV23(db, orgId, env, params),
]);
console.log(chalk.gray(` ${summarize("V2.2", v22)}`));
console.log(chalk.gray(` ${summarize("V2.3", v23)}`));
const diff = findDiff(v22, v23);
if (diff) {
console.log(chalk.red(` ❌ DIFF at ${diff}`));
const idx = diff.match(/\$\[(\d+)\]/);
if (idx) {
const i = parseInt(idx[1]!, 10);
console.log(chalk.gray(` --- V2.2 [${i}] ---`));
console.log(chalk.gray(JSON.stringify(v22[i], null, 2).slice(0, 4000)));
console.log(chalk.gray(` --- V2.3 [${i}] ---`));
console.log(chalk.gray(JSON.stringify(v23[i], null, 2).slice(0, 4000)));
}
} else {
console.log(chalk.green(` ✓ MATCH`));
passes++;
}
}
console.log(
chalk.magentaBright(`\n ${label}: ${passes}/${total} cases match`),
);
return { total, passes };
};
const main = async () => {
const { db, client } = initDrizzle();
try {
let grandTotal = 0;
let grandPasses = 0;
for (const org of ORGS) {
try {
const { total, passes } = await runOrg({
db,
orgId: org.id,
env: org.env,
label: org.label,
});
grandTotal += total;
grandPasses += passes;
} catch (err) {
console.error(chalk.red(`\n❌ Org ${org.label} failed:`), err);
}
}
console.log(
chalk.magentaBright(
`\n========= TOTAL: ${grandPasses}/${grandTotal} cases match =========\n`,
),
);
} catch (error) {
console.error(chalk.red("\n❌ Diff failed:"));
console.error(error);
process.exit(1);
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,52 @@
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const main = async () => {
const { db, client } = initDrizzle();
try {
const tables = [
"customers",
"customer_products",
"customer_entitlements",
"customer_prices",
"subscriptions",
];
for (const t of tables) {
console.log(chalk.bold(`\n=== ${t} indexes ===`));
const r = (await db.execute(sql.raw(`
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = '${t}' AND schemaname = 'public'
ORDER BY indexname
`))) as unknown as { indexname: string; indexdef: string }[];
for (const idx of r) {
console.log(` ${idx.indexname}`);
console.log(` ${idx.indexdef}`);
}
}
// Get total rows in customer_products across all orgs
console.log(chalk.bold("\n=== Global customer_products stats ==="));
const stats = (await db.execute(sql.raw(`
SELECT
reltuples::bigint AS estimated_rows,
pg_size_pretty(pg_relation_size('customer_products')) AS table_size,
pg_size_pretty(pg_indexes_size('customer_products')) AS indexes_size
FROM pg_class WHERE relname = 'customer_products'
`))) as unknown as { estimated_rows: string; table_size: string; indexes_size: string }[];
console.log(` estimated_rows=${stats[0].estimated_rows} table=${stats[0].table_size} indexes=${stats[0].indexes_size}`);
// Actual count globally
const real = (await db.execute(sql.raw(`SELECT COUNT(*)::int AS n FROM customer_products`))) as unknown as { n: number }[];
console.log(` actual_total_rows=${real[0].n.toLocaleString()}`);
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,90 @@
import chalk from "chalk";
import { sql } from "drizzle-orm";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const ORG_ID = "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt";
const main = async () => {
const { db, client } = initDrizzle();
try {
const tables = [
"customers",
"customer_products",
"customer_entitlements",
"customer_prices",
"subscriptions",
"entitlements",
"products",
"rollovers",
"replaceables",
"free_trials",
];
console.log(chalk.bold(`\nRow counts for org=${ORG_ID}:\n`));
for (const t of tables) {
const hasOrg = ["customers", "subscriptions", "entitlements", "products", "features"];
const col = hasOrg.includes(t)
? `WHERE org_id = '${ORG_ID}'`
: t === "customer_products" ||
t === "customer_entitlements" ||
t === "customer_prices"
? `WHERE internal_customer_id IN (SELECT internal_id FROM customers WHERE org_id = '${ORG_ID}')`
: "";
const start = performance.now();
const r = (await db.execute(
sql.raw(`SELECT COUNT(*)::int AS n FROM ${t} ${col}`),
)) as unknown as { n: number }[];
const n = r[0]?.n ?? 0;
console.log(
` ${t.padEnd(28)} ${n.toLocaleString().padStart(10)} (${(performance.now() - start).toFixed(0)}ms)`,
);
}
// Sample a customer to see if it has any products
const sample = (await db.execute(sql.raw(`
SELECT c.internal_id, c.id,
(SELECT COUNT(*)::int FROM customer_products cp WHERE cp.internal_customer_id = c.internal_id) AS cp_count,
(SELECT COUNT(*)::int FROM customer_entitlements ce WHERE ce.internal_customer_id = c.internal_id) AS ce_count
FROM customers c
WHERE c.org_id = '${ORG_ID}'
ORDER BY c.created_at DESC
LIMIT 10
`))) as unknown as Record<string, unknown>[];
console.log(chalk.bold(`\nFirst 10 customers by created_at DESC:\n`));
for (const row of sample) {
console.log(
` ${(row.id as string).padEnd(30)} cp=${row.cp_count} ce=${row.ce_count}`,
);
}
// Histogram: how many customers have N products?
const hist = (await db.execute(sql.raw(`
SELECT cp_bucket, COUNT(*)::int AS customer_count FROM (
SELECT c.internal_id,
LEAST(
(SELECT COUNT(*)::int FROM customer_products cp WHERE cp.internal_customer_id = c.internal_id),
10
) AS cp_bucket
FROM customers c
WHERE c.org_id = '${ORG_ID}'
) t
GROUP BY cp_bucket
ORDER BY cp_bucket
`))) as unknown as { cp_bucket: number; customer_count: number }[];
console.log(chalk.bold(`\nCustomer × #products histogram (capped at 10):\n`));
for (const row of hist) {
const bar = "█".repeat(Math.min(60, Math.floor(row.customer_count / 5000)));
console.log(
` ${row.cp_bucket.toString().padStart(2)}: ${row.customer_count.toLocaleString().padStart(8)} ${bar}`,
);
}
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,174 @@
-- ============================================================
-- Variant 00: baseline (current getCursorPaginatedFullCusQuery)
-- Deep page (cursor ≈ 45% of 1.22M customers), limit=1000
-- Target org: Firecrawl
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH customer_records AS (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
AND (c.created_at, c.id) < (1774237983361, '772c9569-fc97-4c30-9fd8-c8a585b66755')
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
customer_products_with_prices AS (
SELECT
cp.*,
row_to_json(prod) AS product,
cpr_data.customer_prices,
ce_data.customer_entitlements,
ft_data.free_trial
FROM customer_records cr
JOIN LATERAL (
SELECT *
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
LEFT JOIN LATERAL (
SELECT COALESCE(
json_agg(
to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))
) FILTER (WHERE cpr.id IS NOT NULL),
'[]'::json
) AS customer_prices
FROM customer_prices cpr
LEFT JOIN prices p ON cpr.price_id = p.id
WHERE cpr.customer_product_id = cp.id
) cpr_data ON true
LEFT JOIN LATERAL (
SELECT COALESCE(
json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', (
SELECT COALESCE(
json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL),
'[]'::json
)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
),
'rollovers', (
SELECT COALESCE(
json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST) FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL),
'[]'::json
)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
)
)
) FILTER (WHERE ce.id IS NOT NULL),
'[]'::json
) AS customer_entitlements
FROM customer_entitlements ce
WHERE ce.customer_product_id = cp.id
) ce_data ON true
LEFT JOIN LATERAL (
SELECT row_to_json(ft) AS free_trial
FROM free_trials ft
WHERE ft.id = cp.free_trial_id
) ft_data ON true
),
customer_products_aggregated AS (
SELECT
cpwp.internal_customer_id,
json_agg(row_to_json(cpwp) ORDER BY cpwp.created_at DESC) AS customer_products
FROM customer_products_with_prices cpwp
GROUP BY cpwp.internal_customer_id
),
customer_subscriptions AS (
SELECT
s.internal_customer_id,
COALESCE(
json_agg(row_to_json(s)) FILTER (WHERE s.stripe_id IS NOT NULL),
'[]'::json
) AS subscriptions
FROM (
SELECT DISTINCT
cpwp.internal_customer_id,
s.*
FROM customer_products_with_prices cpwp
JOIN LATERAL unnest(cpwp.subscription_ids) AS cpwp_sub(stripe_id) ON true
JOIN subscriptions s ON s.stripe_id = cpwp_sub.stripe_id
) s
GROUP BY s.internal_customer_id
),
extra_customer_entitlements AS (
SELECT
cr.internal_id AS internal_customer_id,
COALESCE(
json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', (
SELECT COALESCE(
json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL),
'[]'::json
)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
),
'rollovers', (
SELECT COALESCE(
json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST)
FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL),
'[]'::json
)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
)
)
ORDER BY ce.id DESC
) FILTER (WHERE ce.id IS NOT NULL),
'[]'::json
) AS extra_customer_entitlements
FROM customer_records cr
LEFT JOIN LATERAL (
SELECT *
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
GROUP BY cr.internal_id
)
SELECT
cr.*,
COALESCE(cpa.customer_products, '[]'::json) AS customer_products,
COALESCE(cs.subscriptions, '[]'::json) AS subscriptions,
COALESCE(ece.extra_customer_entitlements, '[]'::json) AS extra_customer_entitlements
FROM customer_records cr
LEFT JOIN customer_products_aggregated cpa ON cpa.internal_customer_id = cr.internal_id
LEFT JOIN customer_subscriptions cs ON cs.internal_customer_id = cr.internal_id
LEFT JOIN extra_customer_entitlements ece ON ece.internal_customer_id = cr.internal_id
ORDER BY cr.created_at DESC, cr.id DESC;

View File

@@ -0,0 +1,173 @@
-- ============================================================
-- Variant 00: baseline (current getCursorPaginatedFullCusQuery)
-- Page 1, limit=1000, withSubs=true, full CTE pipeline
-- Target org: Firecrawl
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH customer_records AS (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
customer_products_with_prices AS (
SELECT
cp.*,
row_to_json(prod) AS product,
cpr_data.customer_prices,
ce_data.customer_entitlements,
ft_data.free_trial
FROM customer_records cr
JOIN LATERAL (
SELECT *
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
LEFT JOIN LATERAL (
SELECT COALESCE(
json_agg(
to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))
) FILTER (WHERE cpr.id IS NOT NULL),
'[]'::json
) AS customer_prices
FROM customer_prices cpr
LEFT JOIN prices p ON cpr.price_id = p.id
WHERE cpr.customer_product_id = cp.id
) cpr_data ON true
LEFT JOIN LATERAL (
SELECT COALESCE(
json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', (
SELECT COALESCE(
json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL),
'[]'::json
)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
),
'rollovers', (
SELECT COALESCE(
json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST) FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL),
'[]'::json
)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
)
)
) FILTER (WHERE ce.id IS NOT NULL),
'[]'::json
) AS customer_entitlements
FROM customer_entitlements ce
WHERE ce.customer_product_id = cp.id
) ce_data ON true
LEFT JOIN LATERAL (
SELECT row_to_json(ft) AS free_trial
FROM free_trials ft
WHERE ft.id = cp.free_trial_id
) ft_data ON true
),
customer_products_aggregated AS (
SELECT
cpwp.internal_customer_id,
json_agg(row_to_json(cpwp) ORDER BY cpwp.created_at DESC) AS customer_products
FROM customer_products_with_prices cpwp
GROUP BY cpwp.internal_customer_id
),
customer_subscriptions AS (
SELECT
s.internal_customer_id,
COALESCE(
json_agg(row_to_json(s)) FILTER (WHERE s.stripe_id IS NOT NULL),
'[]'::json
) AS subscriptions
FROM (
SELECT DISTINCT
cpwp.internal_customer_id,
s.*
FROM customer_products_with_prices cpwp
JOIN LATERAL unnest(cpwp.subscription_ids) AS cpwp_sub(stripe_id) ON true
JOIN subscriptions s ON s.stripe_id = cpwp_sub.stripe_id
) s
GROUP BY s.internal_customer_id
),
extra_customer_entitlements AS (
SELECT
cr.internal_id AS internal_customer_id,
COALESCE(
json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', (
SELECT COALESCE(
json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL),
'[]'::json
)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
),
'rollovers', (
SELECT COALESCE(
json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST)
FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL),
'[]'::json
)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
)
)
ORDER BY ce.id DESC
) FILTER (WHERE ce.id IS NOT NULL),
'[]'::json
) AS extra_customer_entitlements
FROM customer_records cr
LEFT JOIN LATERAL (
SELECT *
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
GROUP BY cr.internal_id
)
SELECT
cr.*,
COALESCE(cpa.customer_products, '[]'::json) AS customer_products,
COALESCE(cs.subscriptions, '[]'::json) AS subscriptions,
COALESCE(ece.extra_customer_entitlements, '[]'::json) AS extra_customer_entitlements
FROM customer_records cr
LEFT JOIN customer_products_aggregated cpa ON cpa.internal_customer_id = cr.internal_id
LEFT JOIN customer_subscriptions cs ON cs.internal_customer_id = cr.internal_id
LEFT JOIN extra_customer_entitlements ece ON ece.internal_customer_id = cr.internal_id
ORDER BY cr.created_at DESC, cr.id DESC;

View File

@@ -0,0 +1,131 @@
-- ============================================================
-- Variant 01: inline correlated subqueries (no cpwp CTE)
-- Page 1, limit=1000, withSubs=true
-- Target org: Firecrawl
--
-- Hypothesis: eliminating the materialize-then-group-then-sort
-- of customer_products_with_prices saves the 180ms sort that
-- dominated the baseline. Per-row LATERAL keeps json_agg local.
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH customer_records AS (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
)
SELECT
cr.*,
COALESCE((
SELECT json_agg(row_to_json(cp_full) ORDER BY cp_full.created_at DESC)
FROM (
SELECT
cp.*,
row_to_json(prod) AS product,
COALESCE((
SELECT json_agg(
to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))
) FILTER (WHERE cpr.id IS NOT NULL)
FROM customer_prices cpr
LEFT JOIN prices p ON cpr.price_id = p.id
WHERE cpr.customer_product_id = cp.id
), '[]'::json) AS customer_prices,
COALESCE((
SELECT json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', COALESCE((
SELECT json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
), '[]'::json),
'rollovers', COALESCE((
SELECT json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST)
FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
), '[]'::json)
)
) FILTER (WHERE ce.id IS NOT NULL)
FROM customer_entitlements ce
WHERE ce.customer_product_id = cp.id
), '[]'::json) AS customer_entitlements,
(
SELECT row_to_json(ft)
FROM free_trials ft
WHERE ft.id = cp.free_trial_id
) AS free_trial
FROM customer_products cp
JOIN products prod ON cp.internal_product_id = prod.internal_id
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY prod.is_add_on ASC, cp.created_at DESC
LIMIT 15
) cp_full
), '[]'::json) AS customer_products,
COALESCE((
SELECT json_agg(row_to_json(s_distinct)) FILTER (WHERE s_distinct.stripe_id IS NOT NULL)
FROM (
SELECT DISTINCT
cp_sub.internal_customer_id,
s.*
FROM customer_products cp_sub
CROSS JOIN LATERAL unnest(cp_sub.subscription_ids) AS sub_id_t(sub_id)
JOIN subscriptions s ON s.stripe_id = sub_id_t.sub_id
WHERE cp_sub.internal_customer_id = cr.internal_id
AND cp_sub.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
) s_distinct
), '[]'::json) AS subscriptions,
COALESCE((
SELECT json_agg(ce_full.ce_obj ORDER BY ce_full.ce_id DESC)
FROM (
SELECT
ce.id AS ce_id,
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', COALESCE((
SELECT json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
), '[]'::json),
'rollovers', COALESCE((
SELECT json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST)
FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
), '[]'::json)
) AS ce_obj
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce_full
), '[]'::json) AS extra_customer_entitlements
FROM customer_records cr
ORDER BY cr.created_at DESC, cr.id DESC;

View File

@@ -0,0 +1,127 @@
-- ============================================================
-- Variant 02: flat bulk fetch (assemble in code)
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Hypothesis: one SQL round-trip, multiple JSON columns each
-- with a bulk-IN-list fetch per relation. No per-row JSON
-- construction, no nested SubPlan per ce, no joins beyond what
-- the planner pulls into hash joins. Application assembles the
-- nested response.
--
-- Includes entity-attached cps (cps where internal_entity_id
-- matches an entity owned by a page-customer). Entities are
-- returned as a separate relation.
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
ents AS MATERIALIZED (
SELECT e.*
FROM entities e
WHERE e.internal_customer_id IN (SELECT internal_id FROM cr)
),
cps_ranked AS MATERIALIZED (
SELECT
cp.*,
ROW_NUMBER() OVER (
PARTITION BY cp.internal_customer_id
ORDER BY p.is_add_on ASC, cp.created_at DESC
) AS rn
FROM customer_products cp
JOIN products p ON p.internal_id = cp.internal_product_id
WHERE cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
AND (
cp.internal_customer_id IN (SELECT internal_id FROM cr)
OR cp.internal_entity_id IN (SELECT internal_id FROM ents)
)
),
cps AS MATERIALIZED (
SELECT * FROM cps_ranked WHERE rn <= 15
),
ces AS MATERIALIZED (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id IN (SELECT id FROM cps)
OR (
ce.internal_customer_id IN (SELECT internal_id FROM cr)
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
)
)
SELECT
(SELECT COALESCE(jsonb_agg(to_jsonb(x) ORDER BY x.created_at DESC, x.id DESC), '[]'::jsonb)
FROM cr x) AS customers,
(SELECT COALESCE(jsonb_agg(to_jsonb(x)), '[]'::jsonb)
FROM ents x) AS entities,
(SELECT COALESCE(jsonb_agg(to_jsonb(x)), '[]'::jsonb)
FROM cps x) AS customer_products,
(SELECT COALESCE(jsonb_agg(to_jsonb(p)), '[]'::jsonb)
FROM products p
WHERE p.internal_id IN (SELECT internal_product_id FROM cps)) AS products,
(SELECT COALESCE(jsonb_agg(to_jsonb(x)), '[]'::jsonb)
FROM ces x) AS customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(e)), '[]'::jsonb)
FROM entitlements e
WHERE e.id IN (SELECT entitlement_id FROM ces)) AS entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(f)), '[]'::jsonb)
FROM features f
WHERE f.internal_id IN (
SELECT e.internal_feature_id::text
FROM entitlements e
WHERE e.id IN (SELECT entitlement_id FROM ces)
)) AS features,
(SELECT COALESCE(jsonb_agg(to_jsonb(cpr)), '[]'::jsonb)
FROM customer_prices cpr
WHERE cpr.customer_product_id IN (SELECT id FROM cps)) AS customer_prices,
(SELECT COALESCE(jsonb_agg(to_jsonb(pr)), '[]'::jsonb)
FROM prices pr
WHERE pr.id IN (
SELECT price_id
FROM customer_prices
WHERE customer_product_id IN (SELECT id FROM cps)
)) AS prices,
(SELECT COALESCE(jsonb_agg(to_jsonb(ro)), '[]'::jsonb)
FROM rollovers ro
WHERE ro.cus_ent_id IN (SELECT id FROM ces)
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)) AS rollovers,
(SELECT COALESCE(jsonb_agg(to_jsonb(r)), '[]'::jsonb)
FROM replaceables r
WHERE r.cus_ent_id IN (SELECT id FROM ces)) AS replaceables,
(SELECT COALESCE(jsonb_agg(to_jsonb(ft)), '[]'::jsonb)
FROM free_trials ft
WHERE ft.id IN (
SELECT free_trial_id FROM cps WHERE free_trial_id IS NOT NULL
)) AS free_trials,
(SELECT COALESCE(jsonb_agg(to_jsonb(s)), '[]'::jsonb)
FROM subscriptions s
WHERE s.stripe_id IN (
SELECT DISTINCT sub_id
FROM cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
WHERE cps.subscription_ids IS NOT NULL
)) AS subscriptions;

View File

@@ -0,0 +1,121 @@
-- ============================================================
-- Variant 03: LATERAL per-row for parents, bulk for leaves
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Hypothesis: variant 02 died because OR predicates + bulk-IN
-- forced seq scans. Fix: keep LATERAL per-row for cps and ces
-- (forces per-key index lookups), then bulk-fetch leaves
-- (entitlements / features / rollovers / replaceables) using
-- a small ce_ids relation as the driver. No JSON build inside
-- inner subplans — flat rows only, app assembles.
--
-- NOTE: skipping entity-attached cps in this variant. The OR
-- on internal_customer_id / internal_entity_id was the killer
-- in variant 02. We can layer entities back in once the base
-- shape is fast.
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.*,
row_to_json(prod) AS product
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (
SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id
) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_bound AS MATERIALIZED (
SELECT ce.*
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
),
ces_loose AS MATERIALIZED (
SELECT ce.*
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
ce_keys AS MATERIALIZED (
SELECT id, entitlement_id FROM ces_bound
UNION ALL
SELECT id, entitlement_id FROM ces_loose
)
SELECT
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*) ORDER BY x.created_at DESC, x.id DESC), '[]'::jsonb)
FROM cr x) AS customers,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb)
FROM cps_flat x) AS customer_products,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb)
FROM ces_bound x) AS customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb)
FROM ces_loose x) AS extra_customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))), '[]'::jsonb)
FROM cps_flat cps
JOIN customer_prices cpr ON cpr.customer_product_id = cps.id
LEFT JOIN prices p ON p.id = cpr.price_id) AS customer_prices,
(SELECT COALESCE(jsonb_agg(to_jsonb(e.*) || jsonb_build_object('feature', to_jsonb(f.*))), '[]'::jsonb)
FROM ce_keys
JOIN entitlements e ON e.id = ce_keys.entitlement_id
JOIN features f ON f.internal_id = e.internal_feature_id) AS entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(ro.*)), '[]'::jsonb)
FROM ce_keys
JOIN rollovers ro ON ro.cus_ent_id = ce_keys.id
WHERE ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000) AS rollovers,
(SELECT COALESCE(jsonb_agg(to_jsonb(r.*)), '[]'::jsonb)
FROM ce_keys
JOIN replaceables r ON r.cus_ent_id = ce_keys.id) AS replaceables,
(SELECT COALESCE(jsonb_agg(to_jsonb(ft.*)), '[]'::jsonb)
FROM cps_flat cps
JOIN free_trials ft ON ft.id = cps.free_trial_id
WHERE cps.free_trial_id IS NOT NULL) AS free_trials,
(SELECT COALESCE(jsonb_agg(to_jsonb(s.*)), '[]'::jsonb)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN subscriptions s ON s.stripe_id = sub_id_t.sub_id
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions;

View File

@@ -0,0 +1,150 @@
-- ============================================================
-- Variant 04: LATERAL for leaves too
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Hypothesis: variant 03's killer was the planner choosing a
-- Merge Join over the full entitlements table because the
-- ce_keys CTE row estimate was 100x off (206k est, 2.8k real).
-- Same in features (53k seq scan + 17MB hash).
--
-- Fix: wrap each leaf bulk fetch in CROSS JOIN LATERAL so the
-- inner subquery executes per-driver-row — forces nested loop
-- index scan regardless of CTE cardinality estimates.
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.*,
row_to_json(prod) AS product
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (
SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id
) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_bound AS MATERIALIZED (
SELECT ce.*
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
),
ces_loose AS MATERIALIZED (
SELECT ce.*
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
ce_keys AS MATERIALIZED (
SELECT id, entitlement_id FROM ces_bound
UNION ALL
SELECT id, entitlement_id FROM ces_loose
)
SELECT
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*) ORDER BY x.created_at DESC, x.id DESC), '[]'::jsonb)
FROM cr x) AS customers,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb)
FROM cps_flat x) AS customer_products,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb)
FROM ces_bound x) AS customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb)
FROM ces_loose x) AS extra_customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))), '[]'::jsonb)
FROM cps_flat cps
CROSS JOIN LATERAL (
SELECT cpr.*
FROM customer_prices cpr
WHERE cpr.customer_product_id = cps.id
) cpr
LEFT JOIN LATERAL (
SELECT p.*
FROM prices p
WHERE p.id = cpr.price_id
) p ON true) AS customer_prices,
(SELECT COALESCE(jsonb_agg(to_jsonb(e.*) || jsonb_build_object('feature', to_jsonb(f.*))), '[]'::jsonb)
FROM ce_keys ck
CROSS JOIN LATERAL (
SELECT e.*
FROM entitlements e
WHERE e.id = ck.entitlement_id
) e
CROSS JOIN LATERAL (
SELECT f.*
FROM features f
WHERE f.internal_id = e.internal_feature_id
) f) AS entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(ro.*)), '[]'::jsonb)
FROM ce_keys ck
CROSS JOIN LATERAL (
SELECT ro.*
FROM rollovers ro
WHERE ro.cus_ent_id = ck.id
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
) ro) AS rollovers,
(SELECT COALESCE(jsonb_agg(to_jsonb(r.*)), '[]'::jsonb)
FROM ce_keys ck
CROSS JOIN LATERAL (
SELECT r.*
FROM replaceables r
WHERE r.cus_ent_id = ck.id
) r) AS replaceables,
(SELECT COALESCE(jsonb_agg(to_jsonb(ft.*)), '[]'::jsonb)
FROM cps_flat cps
CROSS JOIN LATERAL (
SELECT ft.*
FROM free_trials ft
WHERE ft.id = cps.free_trial_id
) ft
WHERE cps.free_trial_id IS NOT NULL) AS free_trials,
(SELECT COALESCE(jsonb_agg(to_jsonb(s.*)), '[]'::jsonb)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
CROSS JOIN LATERAL (
SELECT s.*
FROM subscriptions s
WHERE s.stripe_id = sub_id_t.sub_id
) s
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions;

View File

@@ -0,0 +1,163 @@
-- ============================================================
-- Variant 05: unnest(array_agg) fence to defeat merge join
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Variants 03/04 failed because Postgres pulls up LATERAL +
-- single-equality predicates and re-plans as a merge join over
-- the full entitlements table (2M rows scanned). The bad CTE
-- row estimate (206k vs 2.8k actual) made merge join "look"
-- cheaper.
--
-- Fix: turn ce_keys into a runtime array via `array_agg`,
-- then `unnest` + JOIN LATERAL. The array is a single scalar
-- value to the planner — no row-estimate pullup, no merge join.
-- The unnest output drives nested-loop index lookups one per
-- element.
--
-- Bonus: drop ORDER BY in `jsonb_agg(customers)` since cr is
-- already sorted by created_at DESC, id DESC.
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.*,
row_to_json(prod) AS product
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (
SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id
) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_bound AS MATERIALIZED (
SELECT ce.*
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
),
ces_loose AS MATERIALIZED (
SELECT ce.*
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
ce_arrays AS MATERIALIZED (
SELECT
array_agg(id) AS all_ids,
array_agg(DISTINCT entitlement_id) AS distinct_entitlement_ids
FROM (
SELECT id, entitlement_id FROM ces_bound
UNION ALL
SELECT id, entitlement_id FROM ces_loose
) _
),
cps_arrays AS MATERIALIZED (
SELECT
array_agg(id) AS cp_ids,
array_agg(DISTINCT free_trial_id) FILTER (WHERE free_trial_id IS NOT NULL) AS free_trial_ids
FROM cps_flat
)
SELECT
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb) FROM cr x) AS customers,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb) FROM cps_flat x) AS customer_products,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb) FROM ces_bound x) AS customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(x.*)), '[]'::jsonb) FROM ces_loose x) AS extra_customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))), '[]'::jsonb)
FROM cps_flat cps
JOIN LATERAL (
SELECT cpr.*
FROM customer_prices cpr
WHERE cpr.customer_product_id = cps.id
) cpr ON true
LEFT JOIN LATERAL (
SELECT p.*
FROM prices p
WHERE p.id = cpr.price_id
) p ON true) AS customer_prices,
(SELECT COALESCE(jsonb_agg(to_jsonb(e.*) || jsonb_build_object('feature', to_jsonb(f.*))), '[]'::jsonb)
FROM unnest((SELECT distinct_entitlement_ids FROM ce_arrays)) AS u(entitlement_id)
JOIN LATERAL (
SELECT e.*
FROM entitlements e
WHERE e.id = u.entitlement_id
) e ON true
JOIN LATERAL (
SELECT f.*
FROM features f
WHERE f.internal_id = e.internal_feature_id
) f ON true) AS entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(ro.*)), '[]'::jsonb)
FROM unnest((SELECT all_ids FROM ce_arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT ro.*
FROM rollovers ro
WHERE ro.cus_ent_id = u.ce_id
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
) ro ON true) AS rollovers,
(SELECT COALESCE(jsonb_agg(to_jsonb(r.*)), '[]'::jsonb)
FROM unnest((SELECT all_ids FROM ce_arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT r.*
FROM replaceables r
WHERE r.cus_ent_id = u.ce_id
) r ON true) AS replaceables,
(SELECT COALESCE(jsonb_agg(to_jsonb(ft.*)), '[]'::jsonb)
FROM unnest((SELECT free_trial_ids FROM cps_arrays)) AS u(ft_id)
JOIN LATERAL (
SELECT ft.*
FROM free_trials ft
WHERE ft.id = u.ft_id
) ft ON true) AS free_trials,
(SELECT COALESCE(jsonb_agg(to_jsonb(s.*)), '[]'::jsonb)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN LATERAL (
SELECT s.*
FROM subscriptions s
WHERE s.stripe_id = sub_id_t.sub_id
) s ON true
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions;

View File

@@ -0,0 +1,170 @@
-- ============================================================
-- Variant 06: precompute jsonb at CTE build
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Each CTE stores its row as: (fk columns needed by downstream
-- + a pre-built jsonb_blob column). The final jsonb_agg
-- just collects pre-built blobs — no per-row to_jsonb work
-- during the aggregation scan.
--
-- Expected savings: variant 05 spent ~190ms in jsonb_agg
-- across 4 wide-row CTEs. With pre-built blobs, aggregation
-- becomes a memory walk + array build (~30-50ms).
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT
c.internal_id,
c.id,
c.created_at,
to_jsonb(c.*) AS row_json
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
cp.free_trial_id,
cp.subscription_ids,
to_jsonb(cp.*) || jsonb_build_object('product', to_jsonb(prod.*)) AS row_json
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (
SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id
) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_bound AS MATERIALIZED (
SELECT
ce.id,
ce.entitlement_id,
to_jsonb(ce.*) AS row_json
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
),
ces_loose AS MATERIALIZED (
SELECT
ce.id,
ce.entitlement_id,
to_jsonb(ce.*) AS row_json
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
ce_arrays AS MATERIALIZED (
SELECT
array_agg(id) AS all_ids,
array_agg(DISTINCT entitlement_id) AS distinct_entitlement_ids
FROM (
SELECT id, entitlement_id FROM ces_bound
UNION ALL
SELECT id, entitlement_id FROM ces_loose
) _
),
cps_arrays AS MATERIALIZED (
SELECT
array_agg(DISTINCT free_trial_id) FILTER (WHERE free_trial_id IS NOT NULL) AS free_trial_ids
FROM cps_flat
)
SELECT
(SELECT COALESCE(jsonb_agg(row_json), '[]'::jsonb) FROM cr) AS customers,
(SELECT COALESCE(jsonb_agg(row_json), '[]'::jsonb) FROM cps_flat) AS customer_products,
(SELECT COALESCE(jsonb_agg(row_json), '[]'::jsonb) FROM ces_bound) AS customer_entitlements,
(SELECT COALESCE(jsonb_agg(row_json), '[]'::jsonb) FROM ces_loose) AS extra_customer_entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))), '[]'::jsonb)
FROM cps_flat cps
JOIN LATERAL (
SELECT cpr.*
FROM customer_prices cpr
WHERE cpr.customer_product_id = cps.id
) cpr ON true
LEFT JOIN LATERAL (
SELECT p.*
FROM prices p
WHERE p.id = cpr.price_id
) p ON true) AS customer_prices,
(SELECT COALESCE(jsonb_agg(to_jsonb(e.*) || jsonb_build_object('feature', to_jsonb(f.*))), '[]'::jsonb)
FROM unnest((SELECT distinct_entitlement_ids FROM ce_arrays)) AS u(entitlement_id)
JOIN LATERAL (
SELECT e.*
FROM entitlements e
WHERE e.id = u.entitlement_id
) e ON true
JOIN LATERAL (
SELECT f.*
FROM features f
WHERE f.internal_id = e.internal_feature_id
) f ON true) AS entitlements,
(SELECT COALESCE(jsonb_agg(to_jsonb(ro.*)), '[]'::jsonb)
FROM unnest((SELECT all_ids FROM ce_arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT ro.*
FROM rollovers ro
WHERE ro.cus_ent_id = u.ce_id
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
) ro ON true) AS rollovers,
(SELECT COALESCE(jsonb_agg(to_jsonb(r.*)), '[]'::jsonb)
FROM unnest((SELECT all_ids FROM ce_arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT r.*
FROM replaceables r
WHERE r.cus_ent_id = u.ce_id
) r ON true) AS replaceables,
(SELECT COALESCE(jsonb_agg(to_jsonb(ft.*)), '[]'::jsonb)
FROM unnest((SELECT free_trial_ids FROM cps_arrays)) AS u(ft_id)
JOIN LATERAL (
SELECT ft.*
FROM free_trials ft
WHERE ft.id = u.ft_id
) ft ON true) AS free_trials,
(SELECT COALESCE(jsonb_agg(to_jsonb(s.*)), '[]'::jsonb)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN LATERAL (
SELECT s.*
FROM subscriptions s
WHERE s.stripe_id = sub_id_t.sub_id
) s ON true
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions;

View File

@@ -0,0 +1,151 @@
-- ============================================================
-- Variant 07: switch to json/json_agg + merge ces CTEs
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Three tweaks vs variant 06:
-- 1. Use `row_to_json` + `json_agg` instead of `to_jsonb` +
-- `jsonb_agg`. text format, no binary conversion overhead.
-- 2. Merge ces_bound + ces_loose into one CTE with a kind
-- column. Saves one materialization pass + one scan.
-- 3. Drop the inner Sort Key in cps_flat LATERAL — the
-- SubPlan(is_add_on) lookup per cp + sort costs ~10ms.
-- Most customers have ≤2 cps so the ordering is moot;
-- we still respect ORDER BY cp.created_at DESC.
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT
c.internal_id,
c.id,
c.created_at,
row_to_json(c) AS row_json
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
cp.free_trial_id,
cp.subscription_ids,
(row_to_json(cp)::jsonb || jsonb_build_object('product', row_to_json(prod)))::json AS row_json
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_combined AS MATERIALIZED (
SELECT 'bound'::text AS kind, ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
UNION ALL
SELECT 'loose'::text AS kind, ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
arrays AS MATERIALIZED (
SELECT
(SELECT array_agg(id) FROM ces_combined) AS all_ce_ids,
(SELECT array_agg(DISTINCT entitlement_id) FROM ces_combined) AS distinct_entitlement_ids,
(SELECT array_agg(DISTINCT free_trial_id) FILTER (WHERE free_trial_id IS NOT NULL) FROM cps_flat) AS free_trial_ids
)
SELECT
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cr) AS customers,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cps_flat) AS customer_products,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_combined WHERE kind = 'bound') AS customer_entitlements,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_combined WHERE kind = 'loose') AS extra_customer_entitlements,
(SELECT COALESCE(json_agg(row_to_json(cpr)::jsonb || jsonb_build_object('price', row_to_json(p))), '[]'::json)
FROM cps_flat cps
JOIN LATERAL (
SELECT cpr.*
FROM customer_prices cpr
WHERE cpr.customer_product_id = cps.id
) cpr ON true
LEFT JOIN LATERAL (
SELECT p.*
FROM prices p
WHERE p.id = cpr.price_id
) p ON true) AS customer_prices,
(SELECT COALESCE(json_agg(row_to_json(e)::jsonb || jsonb_build_object('feature', row_to_json(f))), '[]'::json)
FROM unnest((SELECT distinct_entitlement_ids FROM arrays)) AS u(entitlement_id)
JOIN LATERAL (
SELECT e.*
FROM entitlements e
WHERE e.id = u.entitlement_id
) e ON true
JOIN LATERAL (
SELECT f.*
FROM features f
WHERE f.internal_id = e.internal_feature_id
) f ON true) AS entitlements,
(SELECT COALESCE(json_agg(row_to_json(ro)), '[]'::json)
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT ro.*
FROM rollovers ro
WHERE ro.cus_ent_id = u.ce_id
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
) ro ON true) AS rollovers,
(SELECT COALESCE(json_agg(row_to_json(r)), '[]'::json)
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT r.*
FROM replaceables r
WHERE r.cus_ent_id = u.ce_id
) r ON true) AS replaceables,
(SELECT COALESCE(json_agg(row_to_json(ft)), '[]'::json)
FROM unnest((SELECT free_trial_ids FROM arrays)) AS u(ft_id)
JOIN LATERAL (
SELECT ft.*
FROM free_trials ft
WHERE ft.id = u.ft_id
) ft ON true) AS free_trials,
(SELECT COALESCE(json_agg(row_to_json(s)), '[]'::json)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN LATERAL (
SELECT s.*
FROM subscriptions s
WHERE s.stripe_id = sub_id_t.sub_id
) s ON true
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions;

View File

@@ -0,0 +1,328 @@
-- ============================================================
-- Deep page comparison: OLD (limit/offset) vs NEW (cursor v07)
-- Target: page at offset ~550k (45% of 1.22M customers)
-- Target org: Firecrawl
--
-- Both queries return the same shape of data (page of 1000
-- customers with full hydration). The OLD path is the current
-- v2.2 behavior (limit + offset, full CTE pipeline). The NEW
-- path is variant 07 (cursor + array fence + json_agg).
--
-- Run each EXPLAIN block separately to get clean plans.
-- ============================================================
-- ╔══════════════════════════════════════════════════════════╗
-- ║ OLD: limit + offset, current getPaginatedFullCusQuery ║
-- ║ LIMIT 1000 OFFSET 550000 ║
-- ╚══════════════════════════════════════════════════════════╝
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH customer_records AS (
SELECT c.*
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC
LIMIT 1000 OFFSET 550000
),
customer_products_with_prices AS (
SELECT
cp.*,
row_to_json(prod) AS product,
cpr_data.customer_prices,
ce_data.customer_entitlements,
ft_data.free_trial
FROM customer_records cr
JOIN LATERAL (
SELECT *
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY (SELECT p.is_add_on FROM products p WHERE p.internal_id = cp.internal_product_id) ASC, cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
LEFT JOIN LATERAL (
SELECT COALESCE(
json_agg(
to_jsonb(cpr.*) || jsonb_build_object('price', to_jsonb(p.*))
) FILTER (WHERE cpr.id IS NOT NULL),
'[]'::json
) AS customer_prices
FROM customer_prices cpr
LEFT JOIN prices p ON cpr.price_id = p.id
WHERE cpr.customer_product_id = cp.id
) cpr_data ON true
LEFT JOIN LATERAL (
SELECT COALESCE(
json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', (
SELECT COALESCE(
json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL),
'[]'::json
)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
),
'rollovers', (
SELECT COALESCE(
json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST) FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL),
'[]'::json
)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
)
)
) FILTER (WHERE ce.id IS NOT NULL),
'[]'::json
) AS customer_entitlements
FROM customer_entitlements ce
WHERE ce.customer_product_id = cp.id
) ce_data ON true
LEFT JOIN LATERAL (
SELECT row_to_json(ft) AS free_trial
FROM free_trials ft
WHERE ft.id = cp.free_trial_id
) ft_data ON true
),
customer_products_aggregated AS (
SELECT
cpwp.internal_customer_id,
json_agg(row_to_json(cpwp) ORDER BY cpwp.created_at DESC) AS customer_products
FROM customer_products_with_prices cpwp
GROUP BY cpwp.internal_customer_id
),
customer_subscriptions AS (
SELECT
s.internal_customer_id,
COALESCE(
json_agg(row_to_json(s)) FILTER (WHERE s.stripe_id IS NOT NULL),
'[]'::json
) AS subscriptions
FROM (
SELECT DISTINCT
cpwp.internal_customer_id,
s.*
FROM customer_products_with_prices cpwp
JOIN LATERAL unnest(cpwp.subscription_ids) AS cpwp_sub(stripe_id) ON true
JOIN subscriptions s ON s.stripe_id = cpwp_sub.stripe_id
) s
GROUP BY s.internal_customer_id
),
extra_customer_entitlements AS (
SELECT
cr.internal_id AS internal_customer_id,
COALESCE(
json_agg(
to_jsonb(ce.*) || jsonb_build_object(
'entitlement', (
SELECT row_to_json(ent_with_feature)
FROM (
SELECT e.*, row_to_json(f) AS feature
FROM entitlements e
JOIN features f ON e.internal_feature_id = f.internal_id
WHERE e.id = ce.entitlement_id
) AS ent_with_feature
),
'replaceables', (
SELECT COALESCE(
json_agg(row_to_json(r)) FILTER (WHERE r.id IS NOT NULL),
'[]'::json
)
FROM replaceables r
WHERE r.cus_ent_id = ce.id
),
'rollovers', (
SELECT COALESCE(
json_agg(row_to_json(ro) ORDER BY ro.expires_at ASC NULLS LAST)
FILTER (WHERE ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000 OR ro.expires_at IS NULL),
'[]'::json
)
FROM rollovers ro
WHERE ro.cus_ent_id = ce.id
)
)
ORDER BY ce.id DESC
) FILTER (WHERE ce.id IS NOT NULL),
'[]'::json
) AS extra_customer_entitlements
FROM customer_records cr
LEFT JOIN LATERAL (
SELECT *
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
GROUP BY cr.internal_id
)
SELECT
cr.*,
COALESCE(cpa.customer_products, '[]'::json) AS customer_products,
COALESCE(cs.subscriptions, '[]'::json) AS subscriptions,
COALESCE(ece.extra_customer_entitlements, '[]'::json) AS extra_customer_entitlements
FROM customer_records cr
LEFT JOIN customer_products_aggregated cpa ON cpa.internal_customer_id = cr.internal_id
LEFT JOIN customer_subscriptions cs ON cs.internal_customer_id = cr.internal_id
LEFT JOIN extra_customer_entitlements ece ON ece.internal_customer_id = cr.internal_id
ORDER BY cr.created_at DESC;
-- ╔══════════════════════════════════════════════════════════╗
-- ║ NEW: variant 07 — cursor + array fence + json_agg ║
-- ║ Deep cursor at the same boundary as OFFSET 550000 ║
-- ╚══════════════════════════════════════════════════════════╝
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT
c.internal_id,
c.id,
c.created_at,
row_to_json(c) AS row_json
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
AND (c.created_at, c.id) < (1774237983361, '772c9569-fc97-4c30-9fd8-c8a585b66755')
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
cp.free_trial_id,
cp.subscription_ids,
(row_to_json(cp)::jsonb || jsonb_build_object('product', row_to_json(prod)))::json AS row_json
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_combined AS MATERIALIZED (
SELECT 'bound'::text AS kind, ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
UNION ALL
SELECT 'loose'::text AS kind, ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
arrays AS MATERIALIZED (
SELECT
(SELECT array_agg(id) FROM ces_combined) AS all_ce_ids,
(SELECT array_agg(DISTINCT entitlement_id) FROM ces_combined) AS distinct_entitlement_ids,
(SELECT array_agg(DISTINCT free_trial_id) FILTER (WHERE free_trial_id IS NOT NULL) FROM cps_flat) AS free_trial_ids
)
SELECT
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cr) AS customers,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cps_flat) AS customer_products,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_combined WHERE kind = 'bound') AS customer_entitlements,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_combined WHERE kind = 'loose') AS extra_customer_entitlements,
(SELECT COALESCE(json_agg(row_to_json(cpr)::jsonb || jsonb_build_object('price', row_to_json(p))), '[]'::json)
FROM cps_flat cps
JOIN LATERAL (
SELECT cpr.*
FROM customer_prices cpr
WHERE cpr.customer_product_id = cps.id
) cpr ON true
LEFT JOIN LATERAL (
SELECT p.*
FROM prices p
WHERE p.id = cpr.price_id
) p ON true) AS customer_prices,
(SELECT COALESCE(json_agg(row_to_json(e)::jsonb || jsonb_build_object('feature', row_to_json(f))), '[]'::json)
FROM unnest((SELECT distinct_entitlement_ids FROM arrays)) AS u(entitlement_id)
JOIN LATERAL (
SELECT e.*
FROM entitlements e
WHERE e.id = u.entitlement_id
) e ON true
JOIN LATERAL (
SELECT f.*
FROM features f
WHERE f.internal_id = e.internal_feature_id
) f ON true) AS entitlements,
(SELECT COALESCE(json_agg(row_to_json(ro)), '[]'::json)
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT ro.*
FROM rollovers ro
WHERE ro.cus_ent_id = u.ce_id
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
) ro ON true) AS rollovers,
(SELECT COALESCE(json_agg(row_to_json(r)), '[]'::json)
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT r.*
FROM replaceables r
WHERE r.cus_ent_id = u.ce_id
) r ON true) AS replaceables,
(SELECT COALESCE(json_agg(row_to_json(ft)), '[]'::json)
FROM unnest((SELECT free_trial_ids FROM arrays)) AS u(ft_id)
JOIN LATERAL (
SELECT ft.*
FROM free_trials ft
WHERE ft.id = u.ft_id
) ft ON true) AS free_trials,
(SELECT COALESCE(json_agg(row_to_json(s)), '[]'::json)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN LATERAL (
SELECT s.*
FROM subscriptions s
WHERE s.stripe_id = sub_id_t.sub_id
) s ON true
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions;

View File

@@ -0,0 +1,244 @@
-- ============================================================
-- Variant 09: variant 07 + SQL-side reassembly into nested shape
-- Page 1, limit=1000
-- Target org: Firecrawl
--
-- Variant 07 returns 10 flat top-level arrays (app must rebuild
-- nested hierarchy). This variant adds GROUP BY reassembly so
-- the final result is one row { list: [...customers with full
-- nested hierarchy...] } — same shape as the current handler.
--
-- Cost: extra GROUP BY passes (~6 of them) over the materialized
-- CTEs. Should pick HashAggregate (not GroupAggregate with the
-- COLLATE-C sort that killed the baseline). Expected: +30-60ms
-- on top of variant 07's 128ms.
--
-- Key additions vs variant 07:
-- - ces_combined CTE now also stores internal_customer_id and
-- customer_product_id for GROUP BY
-- - Six "by_<parent>" CTEs that hash-group leaves under their
-- parent
-- - Final SELECT joins cr × cps_by_cus × subs_by_cus ×
-- loose_ces_by_cus and emits one customer object per row
-- ============================================================
EXPLAIN (ANALYZE, BUFFERS, VERBOSE, SETTINGS, FORMAT TEXT)
WITH cr AS MATERIALIZED (
SELECT
c.internal_id,
c.id,
c.created_at,
row_to_json(c) AS row_json
FROM customers c
WHERE c.org_id = 'biu9vSF7vghBLSKW1UTDwxHBAivjnPaK'
AND c.env = 'live'
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1001
),
cps_flat AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
cp.free_trial_id,
cp.subscription_ids,
(row_to_json(cp)::jsonb || jsonb_build_object('product', row_to_json(prod)))::jsonb AS row_jsonb
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_combined AS MATERIALIZED (
SELECT
'bound'::text AS kind,
ce.id,
ce.entitlement_id,
ce.internal_customer_id,
ce.customer_product_id,
row_to_json(ce)::jsonb AS row_jsonb
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
UNION ALL
SELECT
'loose'::text AS kind,
ce.id,
ce.entitlement_id,
ce.internal_customer_id,
ce.customer_product_id,
row_to_json(ce)::jsonb AS row_jsonb
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
arrays AS MATERIALIZED (
SELECT
(SELECT array_agg(id) FROM ces_combined) AS all_ce_ids,
(SELECT array_agg(DISTINCT entitlement_id) FROM ces_combined) AS distinct_entitlement_ids,
(SELECT array_agg(DISTINCT free_trial_id) FILTER (WHERE free_trial_id IS NOT NULL) FROM cps_flat) AS free_trial_ids
),
-- ─── leaf lookup tables (one row per leaf, indexed by parent) ─
ents_by_id AS MATERIALIZED (
SELECT
e.id AS entitlement_id,
(row_to_json(e)::jsonb || jsonb_build_object('feature', row_to_json(f)))::jsonb AS ent_obj
FROM unnest((SELECT distinct_entitlement_ids FROM arrays)) AS u(entitlement_id)
JOIN LATERAL (SELECT * FROM entitlements e WHERE e.id = u.entitlement_id) e ON true
JOIN LATERAL (SELECT * FROM features f WHERE f.internal_id = e.internal_feature_id) f ON true
),
rollovers_by_ce AS MATERIALIZED (
SELECT
ro.cus_ent_id AS ce_id,
jsonb_agg(row_to_json(ro)::jsonb) AS ros_arr
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT ro.*
FROM rollovers ro
WHERE ro.cus_ent_id = u.ce_id
AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
) ro ON true
GROUP BY ro.cus_ent_id
),
replaceables_by_ce AS MATERIALIZED (
SELECT
r.cus_ent_id AS ce_id,
jsonb_agg(row_to_json(r)::jsonb) AS reps_arr
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (
SELECT r.*
FROM replaceables r
WHERE r.cus_ent_id = u.ce_id
) r ON true
GROUP BY r.cus_ent_id
),
ces_hydrated AS MATERIALIZED (
SELECT
ce.kind,
ce.internal_customer_id,
ce.customer_product_id,
ce.id AS ce_id,
ce.row_jsonb
|| jsonb_build_object('entitlement', e.ent_obj)
|| jsonb_build_object('rollovers', COALESCE(r.ros_arr, '[]'::jsonb))
|| jsonb_build_object('replaceables', COALESCE(rep.reps_arr, '[]'::jsonb))
AS ce_obj
FROM ces_combined ce
LEFT JOIN ents_by_id e ON e.entitlement_id = ce.entitlement_id
LEFT JOIN rollovers_by_ce r ON r.ce_id = ce.id
LEFT JOIN replaceables_by_ce rep ON rep.ce_id = ce.id
),
ces_by_cp AS MATERIALIZED (
SELECT
customer_product_id AS cp_id,
jsonb_agg(ce_obj) AS ces_arr
FROM ces_hydrated
WHERE kind = 'bound'
GROUP BY customer_product_id
),
loose_ces_by_cus AS MATERIALIZED (
SELECT
internal_customer_id,
jsonb_agg(ce_obj ORDER BY ce_id DESC) AS loose_arr
FROM ces_hydrated
WHERE kind = 'loose'
GROUP BY internal_customer_id
),
cprs_by_cp AS MATERIALIZED (
SELECT
cpr.customer_product_id AS cp_id,
jsonb_agg(row_to_json(cpr)::jsonb || jsonb_build_object('price', row_to_json(p))) AS cprs_arr
FROM cps_flat cps
JOIN LATERAL (
SELECT cpr.*
FROM customer_prices cpr
WHERE cpr.customer_product_id = cps.id
) cpr ON true
LEFT JOIN LATERAL (
SELECT p.*
FROM prices p
WHERE p.id = cpr.price_id
) p ON true
GROUP BY cpr.customer_product_id
),
fts_by_id AS MATERIALIZED (
SELECT ft.id AS ft_id, row_to_json(ft)::jsonb AS ft_obj
FROM unnest((SELECT free_trial_ids FROM arrays)) AS u(ft_id)
JOIN LATERAL (SELECT * FROM free_trials ft WHERE ft.id = u.ft_id) ft ON true
),
cps_hydrated AS MATERIALIZED (
SELECT
cps.internal_customer_id,
cps.row_jsonb
|| jsonb_build_object('customer_prices', COALESCE(cprs.cprs_arr, '[]'::jsonb))
|| jsonb_build_object('customer_entitlements', COALESCE(ces.ces_arr, '[]'::jsonb))
|| jsonb_build_object('free_trial', ft.ft_obj)
AS cp_obj
FROM cps_flat cps
LEFT JOIN cprs_by_cp cprs ON cprs.cp_id = cps.id
LEFT JOIN ces_by_cp ces ON ces.cp_id = cps.id
LEFT JOIN fts_by_id ft ON ft.ft_id = cps.free_trial_id
),
cps_by_cus AS MATERIALIZED (
SELECT
internal_customer_id,
jsonb_agg(cp_obj) AS cps_arr
FROM cps_hydrated
GROUP BY internal_customer_id
),
subs_by_cus AS MATERIALIZED (
SELECT
cps.internal_customer_id,
jsonb_agg(DISTINCT row_to_json(s)::jsonb) AS subs_arr
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN LATERAL (
SELECT s.*
FROM subscriptions s
WHERE s.stripe_id = sub_id_t.sub_id
) s ON true
WHERE cps.subscription_ids IS NOT NULL
GROUP BY cps.internal_customer_id
)
SELECT jsonb_agg(
cr.row_json::jsonb
|| jsonb_build_object('customer_products', COALESCE(cps.cps_arr, '[]'::jsonb))
|| jsonb_build_object('subscriptions', COALESCE(s.subs_arr, '[]'::jsonb))
|| jsonb_build_object('extra_customer_entitlements', COALESCE(lc.loose_arr, '[]'::jsonb))
ORDER BY cr.created_at DESC, cr.id DESC
) AS list
FROM cr
LEFT JOIN cps_by_cus cps ON cps.internal_customer_id = cr.internal_id
LEFT JOIN subs_by_cus s ON s.internal_customer_id = cr.internal_id
LEFT JOIN loose_ces_by_cus lc ON lc.internal_customer_id = cr.internal_id;

View File

@@ -0,0 +1,29 @@
# List Customers SQL Optimization
Hand-rolled SQL variants for iterating toward 100ms per page on the list customers cursor query.
## Test fixture
- **Org**: Firecrawl (`biu9vSF7vghBLSKW1UTDwxHBAivjnPaK`)
- **Env**: `live`
- **Limit**: 1000
- **Deep cursor**: `{ t: 1774237983361, id: "772c9569-fc97-4c30-9fd8-c8a585b66755" }` (~45% into ~1.22M customers)
## Variants
| # | File | What changed | Median ms (page 1 / deep) |
|---|------|--------------|---------------------------|
| 00 | `00-baseline-{page1,deep}.sql` | Current `getCursorPaginatedFullCusQuery`, full CTE pipeline, withSubs=true | TBD / TBD |
## How to run
```sh
cat 00-baseline-page1.sql | pbcopy # paste into Table+
cat 00-baseline-deep.sql | pbcopy
```
Or directly via psql with prod DATABASE_URL set.
## Goal
100ms per page (both first and deep). Currently ~2480ms on Firecrawl per the prior benchmark.

View File

@@ -0,0 +1,173 @@
import type {
AppEnv,
CusProductStatus,
ListCustomersV2Params,
StandardCursorFields,
} from "@autumn/shared";
import { sql } from "drizzle-orm";
import { getCustomerListFilterSql } from "../src/internal/customers/getFullCusQuery";
export type OptimizedQueryArgs = {
orgId: string;
env: AppEnv;
inStatuses?: CusProductStatus[];
withSubs?: boolean;
limit: number;
cursor?: StandardCursorFields;
internalCustomerIds?: string[];
plans?: ListCustomersV2Params["plans"];
processors?: ListCustomersV2Params["processors"];
search?: string;
cusProductLimit: number;
};
/**
* Set-based replacement for the per-customer LATERAL nested loops.
* Key change: each child fetch is a single hash/merge join over the cr CTE
* instead of 1001 sequential scans (original Seq Scan-per-loop pattern).
*/
export const getOptimizedFullCusQuery = ({
orgId,
env,
inStatuses,
withSubs = true,
limit,
cursor,
internalCustomerIds,
plans,
processors,
search,
cusProductLimit,
}: OptimizedQueryArgs) => {
const cpStatusFilter = inStatuses?.length
? sql`AND cp.status = ANY(ARRAY[${sql.join(
inStatuses.map((status) => sql`${status}`),
sql`, `,
)}])`
: sql``;
const customerListFilterSql = getCustomerListFilterSql({
internalCustomerIds,
inStatuses,
plans,
processors,
search,
});
const cursorPredicate = cursor
? sql`AND (c.created_at, c.id) < (${cursor.t}, ${cursor.id})`
: sql``;
const fetchLimit = limit + 1;
const subscriptionsSelect = withSubs
? sql`(
SELECT COALESCE(json_agg(row_to_json(s)), '[]'::json)
FROM (
SELECT DISTINCT s.*
FROM cps_ranked cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN subscriptions s ON s.stripe_id = sub_id_t.sub_id
WHERE cps.subscription_ids IS NOT NULL
) s
) AS subscriptions`
: sql`'[]'::json AS subscriptions`;
return sql`
WITH cr AS MATERIALIZED (
SELECT
c.internal_id,
c.id,
c.created_at,
row_to_json(c) AS row_json
FROM customers c
WHERE c.org_id = ${orgId}
AND c.env = ${env}
${customerListFilterSql}
${cursorPredicate}
ORDER BY c.created_at DESC, c.id DESC
LIMIT ${fetchLimit}
),
cp_ranked_ids AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
ROW_NUMBER() OVER (
PARTITION BY cp.internal_customer_id
ORDER BY prod.is_add_on ASC, cp.created_at DESC
) AS rn
FROM cr
JOIN customer_products cp ON cp.internal_customer_id = cr.internal_id
JOIN products prod ON prod.internal_id = cp.internal_product_id
WHERE TRUE ${cpStatusFilter}
),
cps_ranked AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
cp.free_trial_id,
cp.subscription_ids,
(row_to_json(cp)::jsonb || jsonb_build_object('product', row_to_json(prod)))::json AS row_json
FROM cp_ranked_ids r
JOIN customer_products cp ON cp.id = r.id
JOIN products prod ON prod.internal_id = r.internal_product_id
WHERE r.rn <= ${cusProductLimit}
),
ces_bound AS MATERIALIZED (
-- Single hash join instead of 1001 LATERAL scans.
SELECT ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cps_ranked
JOIN customer_entitlements ce ON ce.customer_product_id = cps_ranked.id
),
ces_loose AS MATERIALIZED (
-- LATERAL with LIMIT 30 stays; existing partial index is well-suited.
SELECT ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
ces_all AS MATERIALIZED (
SELECT id, entitlement_id FROM ces_bound
UNION ALL
SELECT id, entitlement_id FROM ces_loose
)
SELECT
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cr) AS customers,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cps_ranked) AS customer_products,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_bound) AS customer_entitlements,
(SELECT COALESCE(json_agg(row_json ORDER BY id DESC), '[]'::json) FROM ces_loose) AS extra_customer_entitlements,
(SELECT COALESCE(json_agg(row_to_json(cpr)::jsonb || jsonb_build_object('price', row_to_json(p))), '[]'::json)
FROM cps_ranked
JOIN customer_prices cpr ON cpr.customer_product_id = cps_ranked.id
LEFT JOIN prices p ON p.id = cpr.price_id
) AS customer_prices,
(SELECT COALESCE(json_agg(row_to_json(e)::jsonb || jsonb_build_object('feature', row_to_json(f))), '[]'::json)
FROM (SELECT DISTINCT entitlement_id FROM ces_all) ce
JOIN entitlements e ON e.id = ce.entitlement_id
JOIN features f ON f.internal_id = e.internal_feature_id
) AS entitlements,
(SELECT COALESCE(json_agg(row_to_json(ro)), '[]'::json)
FROM ces_all
JOIN rollovers ro ON ro.cus_ent_id = ces_all.id
WHERE ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000
) AS rollovers,
(SELECT COALESCE(json_agg(row_to_json(r)), '[]'::json)
FROM ces_all
JOIN replaceables r ON r.cus_ent_id = ces_all.id
) AS replaceables,
(SELECT COALESCE(json_agg(row_to_json(ft)), '[]'::json)
FROM (SELECT DISTINCT free_trial_id FROM cps_ranked WHERE free_trial_id IS NOT NULL) cps
JOIN free_trials ft ON ft.id = cps.free_trial_id
) AS free_trials,
${subscriptionsSelect}
`;
};

View File

@@ -6,7 +6,7 @@ import { join } from "node:path";
import { RELEVANT_STATUSES } from "../src/internal/customers/cusProducts/CusProductService";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
import { getCursorPaginatedFullCusQuery } from "./cursorPaginatedFullCusQuery";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
loadLocalEnv();
@@ -158,7 +158,7 @@ const resolveRevenuecatDeepCursor = async ({
}: {
db: DB;
deepOffset: number;
}): Promise<{ createdAt: number; id: string }> => {
}): Promise<{ v: 0; t: number; id: string }> => {
const result = await runQueryInTxn({
db,
query: sql`
@@ -182,13 +182,13 @@ const resolveRevenuecatDeepCursor = async ({
`Could not resolve revenuecat deep cursor at offset ${deepOffset}. Not enough revenuecat customers.`,
);
}
return { createdAt: row.created_at, id: row.id };
return { v: 0, t: row.created_at, id: row.id };
};
const buildCells = ({
deepCursor,
}: {
deepCursor: { createdAt: number; id: string };
deepCursor: { v: 0; t: number; id: string };
}): Cell[] => {
return [
{
@@ -227,7 +227,7 @@ const renderResults = ({
}: {
totalCount: number;
deepOffset: number;
deepCursor: { createdAt: number; id: string };
deepCursor: { v: 0; t: number; id: string };
results: CellResult[];
}): string => {
const date = new Date().toISOString().slice(0, 10);
@@ -244,7 +244,7 @@ const renderResults = ({
`- deep_offset (${DEEP_OFFSET_PCT}% within revcat subset): \`${deepOffset.toLocaleString()}\``,
);
lines.push(
`- deep_cursor (revcat-aware): \`{ t: ${deepCursor.createdAt}, id: ${deepCursor.id} }\``,
`- deep_cursor (revcat-aware): \`{ t: ${deepCursor.t}, id: ${deepCursor.id} }\``,
);
lines.push(`- limit: \`${BASE_LIMIT}\``);
lines.push(`- repeats per cell: ${REPEATS}`);
@@ -308,7 +308,7 @@ const main = async () => {
);
const deepCursor = await resolveRevenuecatDeepCursor({ db, deepOffset });
console.log(
chalk.gray(` cursor = { t: ${deepCursor.createdAt}, id: ${deepCursor.id} }`),
chalk.gray(` cursor = { t: ${deepCursor.t}, id: ${deepCursor.id} }`),
);
console.log();

View File

@@ -0,0 +1,678 @@
import { AppEnv, CusProductStatus, type ListCustomersV2Params } from "@autumn/shared";
import chalk from "chalk";
import { sql, type SQL } from "drizzle-orm";
import { writeFileSync } from "node:fs";
import { join } from "node:path";
import { initDrizzle } from "../src/db/initDrizzle";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
import { getPaginatedFullCusQuery } from "../src/internal/customers/getFullCusQuery";
import { RELEVANT_STATUSES } from "../src/internal/customers/cusProducts/CusProductService";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
// Runs against whatever DATABASE_URL points at. Intentionally bypasses
// the prod-safety guard — laptop → prod is the entire point.
const FIRECRAWL_ORG_ID = "biu9vSF7vghBLSKW1UTDwxHBAivjnPaK";
const RUNABLE_ORG_ID = "r7pwHiekGsqt32qGqcVku6thWFh5aHh8";
const ENV: AppEnv = AppEnv.Live;
const BASE_LIMIT = 1000;
const REPEATS = 5;
const STATEMENT_TIMEOUT_MS = 60_000;
const READ_ONLY = true;
const CUS_PRODUCT_LIMIT = 15;
const DEEP_OFFSET_PCT = 45;
const FIRECRAWL_BASELINE_DEEP_OFFSET = 950_000;
const PLAN_MASSIVE = "free";
const PLAN_MID = "hobby";
const PLAN_RARE = "scale_monthly";
const SEARCH_GMAIL = "@gmail";
const RESULTS_DIR = join(import.meta.dir, "results");
type DB = ReturnType<typeof initDrizzle>["db"];
type Cursor = { v: 0; t: number; id: string };
type FilterOverrides = {
inStatuses?: CusProductStatus[];
search?: string;
plans?: ListCustomersV2Params["plans"];
processors?: ListCustomersV2Params["processors"];
internalCustomerIds?: string[];
};
type Scenario = {
key: string;
label: string;
org: "firecrawl" | "runable";
orgId: string;
filter: FilterOverrides;
withDeep: boolean;
deepOffset?: number;
deepCursor?: Cursor;
};
type Cell = {
scenarioKey: string;
scenarioLabel: string;
org: "firecrawl" | "runable";
queryShape: "offset" | "cursor";
depth: "page1" | "deep";
build: () => SQL;
};
type CellResult = Cell & {
medianMs: number;
p95Ms: number;
minMs: number;
maxMs: number;
rowCount: number;
samples: number[];
error?: string;
};
const sharedFullCusOpts = {
includeInvoices: false,
withEntities: false,
withTrialsUsed: false,
withSubs: true,
cusProductLimit: CUS_PRODUCT_LIMIT,
};
const normalizeRows = (r: unknown): Record<string, unknown>[] => {
if (Array.isArray(r)) return r as Record<string, unknown>[];
if (r && typeof r === "object" && "rows" in r) {
return (r as { rows: Record<string, unknown>[] }).rows;
}
return [];
};
const runQueryInTxn = async ({
db,
query,
}: { db: DB; query: SQL }): Promise<Record<string, unknown>[]> => {
return await db.transaction(async (tx) => {
await tx.execute(
sql.raw(`SET LOCAL statement_timeout = ${STATEMENT_TIMEOUT_MS}`),
);
if (READ_ONLY) {
await tx.execute(sql.raw("SET LOCAL transaction_read_only = on"));
}
return normalizeRows(await tx.execute(query));
});
};
const measureCell = async ({
db,
cell,
}: { db: DB; cell: Cell }): Promise<CellResult> => {
const samples: number[] = [];
let rowCount = 0;
let error: string | undefined;
for (let i = 0; i < REPEATS; i++) {
const query = cell.build();
const startedAt = performance.now();
try {
const result = await runQueryInTxn({ db, query });
const elapsed = performance.now() - startedAt;
samples.push(elapsed);
rowCount = result.length;
} catch (err) {
const elapsed = performance.now() - startedAt;
samples.push(elapsed);
error = err instanceof Error ? err.message : String(err);
break;
}
}
const sorted = [...samples].sort((a, b) => a - b);
const median = sorted[Math.floor(sorted.length / 2)] ?? 0;
const p95 =
sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95))] ?? 0;
const min = sorted[0] ?? 0;
const max = sorted[sorted.length - 1] ?? 0;
return {
...cell,
medianMs: median,
p95Ms: p95,
minMs: min,
maxMs: max,
rowCount,
samples,
error,
};
};
// Per-filter predicate matching getCustomerListFilterSql, used by the
// resolver helpers (count + deep cursor) so deep cells are filter-aware.
const filterPredicate = (f: FilterOverrides): SQL => {
const parts: SQL[] = [];
if (f.internalCustomerIds?.length) {
parts.push(
sql`AND c.internal_id IN (${sql.join(
f.internalCustomerIds.map((id) => sql`${id}`),
sql`, `,
)})`,
);
}
if (f.plans?.length) {
const planConditions = f.plans.map((plan) => {
if (plan.versions?.length) {
return sql`(p_filter.id = ${plan.id} AND p_filter.version IN (${sql.join(
plan.versions.map((v) => sql`${v}`),
sql`, `,
)}))`;
}
return sql`p_filter.id = ${plan.id}`;
});
parts.push(sql`AND EXISTS (
SELECT 1
FROM customer_products cp_filter
JOIN products p_filter ON cp_filter.internal_product_id = p_filter.internal_id
WHERE cp_filter.internal_customer_id = c.internal_id
${
f.inStatuses?.length
? sql`AND cp_filter.status = ANY(ARRAY[${sql.join(
f.inStatuses.map((s) => sql`${s}`),
sql`, `,
)}])`
: sql``
}
AND (${sql.join(planConditions, sql` OR `)})
)`);
}
const trimmedSearch = f.search?.trim();
if (trimmedSearch) {
const pattern = `%${trimmedSearch}%`;
parts.push(sql`AND (
c.id ILIKE ${pattern}
OR c.name ILIKE ${pattern}
OR c.email ILIKE ${pattern}
)`);
}
if (f.processors?.length) {
const procConditions = f.processors
.map((proc) => {
if (proc === "stripe") return sql`(c.processor->>'id' IS NOT NULL)`;
if (proc === "revenuecat")
return sql`EXISTS (
SELECT 1
FROM customer_products cp_processor
WHERE cp_processor.internal_customer_id = c.internal_id
AND cp_processor.processor->>'type' = 'revenuecat'
)`;
if (proc === "vercel") return sql`(c.processors->>'vercel' IS NOT NULL)`;
return null;
})
.filter((c): c is SQL => c !== null);
if (procConditions.length) {
parts.push(sql`AND (${sql.join(procConditions, sql` OR `)})`);
}
}
return parts.length ? sql.join(parts, sql` `) : sql``;
};
const resolveCount = async ({
db,
orgId,
filter,
}: { db: DB; orgId: string; filter: FilterOverrides }): Promise<number> => {
const predicate = filterPredicate(filter);
const rows = await runQueryInTxn({
db,
query: sql`
SELECT COUNT(*)::int AS total_count
FROM customers c
WHERE c.org_id = ${orgId}
AND c.env = ${ENV}
${predicate}
`,
});
return (rows[0] as { total_count: number }).total_count;
};
const resolveDeepCursor = async ({
db,
orgId,
filter,
deepOffset,
}: {
db: DB;
orgId: string;
filter: FilterOverrides;
deepOffset: number;
}): Promise<Cursor> => {
const predicate = filterPredicate(filter);
const rows = await runQueryInTxn({
db,
query: sql`
SELECT c.created_at, c.id
FROM customers c
WHERE c.org_id = ${orgId}
AND c.env = ${ENV}
${predicate}
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1 OFFSET ${deepOffset}
`,
});
const row = rows[0] as { created_at: number; id: string } | undefined;
if (!row) {
throw new Error(
`No row at deep offset ${deepOffset} for filter ${JSON.stringify(filter)}`,
);
}
return { v: 0, t: row.created_at, id: row.id };
};
const resolveFirecrawlInternalIds = async ({
db,
}: { db: DB }): Promise<string[]> => {
const rows = await runQueryInTxn({
db,
query: sql`
SELECT internal_id
FROM customers
WHERE org_id = ${FIRECRAWL_ORG_ID}
AND env = ${ENV}
ORDER BY created_at DESC, id DESC
LIMIT 10
`,
});
return rows.map((r) => (r as { internal_id: string }).internal_id);
};
const buildScenarios = ({
firecrawlInternalIds,
}: { firecrawlInternalIds: string[] }): Scenario[] => {
const fc = (
key: string,
label: string,
filter: FilterOverrides,
withDeep: boolean,
): Scenario => ({
key,
label,
org: "firecrawl",
orgId: FIRECRAWL_ORG_ID,
filter,
withDeep,
});
return [
fc("01-baseline", "none (baseline)", {}, true),
fc("02-search-gmail", `search '${SEARCH_GMAIL}'`, { search: SEARCH_GMAIL }, true),
fc(
"03-status-active",
"inStatuses=['active']",
{ inStatuses: [CusProductStatus.Active] },
true,
),
fc("04-plan-massive", `plans=['${PLAN_MASSIVE}']`, { plans: [{ id: PLAN_MASSIVE }] }, true),
fc("05-plan-mid", `plans=['${PLAN_MID}']`, { plans: [{ id: PLAN_MID }] }, true),
fc("06-plan-rare", `plans=['${PLAN_RARE}']`, { plans: [{ id: PLAN_RARE }] }, false),
fc("07-processor-stripe", "processors=['stripe']", { processors: ["stripe"] }, true),
fc(
"08-internal-ids",
"internalCustomerIds=[10]",
{ internalCustomerIds: firecrawlInternalIds },
false,
),
{
key: "09-processor-revenuecat",
label: "processors=['revenuecat']",
org: "runable",
orgId: RUNABLE_ORG_ID,
filter: { processors: ["revenuecat"] },
withDeep: false,
},
];
};
const buildCellsForScenario = (s: Scenario): Cell[] => {
const inStatuses = s.filter.inStatuses ?? RELEVANT_STATUSES;
const filterArgs = {
inStatuses,
search: s.filter.search,
plans: s.filter.plans,
processors: s.filter.processors,
internalCustomerIds: s.filter.internalCustomerIds,
};
const cells: Cell[] = [
{
scenarioKey: s.key,
scenarioLabel: s.label,
org: s.org,
queryShape: "offset",
depth: "page1",
build: () =>
getPaginatedFullCusQuery({
orgId: s.orgId,
env: ENV,
limit: BASE_LIMIT,
offset: 0,
...sharedFullCusOpts,
...filterArgs,
}),
},
{
scenarioKey: s.key,
scenarioLabel: s.label,
org: s.org,
queryShape: "cursor",
depth: "page1",
build: () =>
getCursorPaginatedFullCusQuery({
orgId: s.orgId,
env: ENV,
limit: BASE_LIMIT,
...sharedFullCusOpts,
...filterArgs,
}),
},
];
if (s.withDeep && s.deepOffset !== undefined && s.deepCursor) {
const deepOffset = s.deepOffset;
const deepCursor = s.deepCursor;
cells.push(
{
scenarioKey: s.key,
scenarioLabel: s.label,
org: s.org,
queryShape: "offset",
depth: "deep",
build: () =>
getPaginatedFullCusQuery({
orgId: s.orgId,
env: ENV,
limit: BASE_LIMIT,
offset: deepOffset,
...sharedFullCusOpts,
...filterArgs,
}),
},
{
scenarioKey: s.key,
scenarioLabel: s.label,
org: s.org,
queryShape: "cursor",
depth: "deep",
build: () =>
getCursorPaginatedFullCusQuery({
orgId: s.orgId,
env: ENV,
limit: BASE_LIMIT,
cursor: deepCursor,
...sharedFullCusOpts,
...filterArgs,
}),
},
);
}
return cells;
};
const pairResults = (
results: CellResult[],
): {
scenarioKey: string;
scenarioLabel: string;
org: string;
depth: "page1" | "deep";
offset?: CellResult;
cursor?: CellResult;
}[] => {
const groups = new Map<
string,
{
scenarioKey: string;
scenarioLabel: string;
org: string;
depth: "page1" | "deep";
offset?: CellResult;
cursor?: CellResult;
}
>();
for (const r of results) {
const key = `${r.scenarioKey}|${r.depth}`;
const group = groups.get(key) ?? {
scenarioKey: r.scenarioKey,
scenarioLabel: r.scenarioLabel,
org: r.org,
depth: r.depth,
};
if (r.queryShape === "offset") group.offset = r;
else group.cursor = r;
groups.set(key, group);
}
return Array.from(groups.values());
};
const fmt = (n: number | undefined): string =>
n === undefined ? "—" : n.toFixed(0);
const renderReport = ({
scenarios,
pairs,
totalWallMs,
dbHost,
}: {
scenarios: Scenario[];
pairs: ReturnType<typeof pairResults>;
totalWallMs: number;
dbHost: string;
}): string => {
const date = new Date().toISOString().slice(0, 10);
const lines: string[] = [];
lines.push(`# Pagination Benchmark — offset vs cursor — ${date}`);
lines.push("");
lines.push("## Config");
lines.push("");
lines.push(`- db host: \`${dbHost}\``);
lines.push(`- env: \`${ENV}\``);
lines.push(`- limit: ${BASE_LIMIT}`);
lines.push(`- repeats per cell: ${REPEATS}`);
lines.push(`- statement_timeout_ms: ${STATEMENT_TIMEOUT_MS}`);
lines.push(`- read_only: ${READ_ONLY}`);
lines.push(`- shared opts: withSubs=true, includeInvoices=false, withEntities=false, withTrialsUsed=false, cusProductLimit=${CUS_PRODUCT_LIMIT}`);
lines.push(`- timings are wall-clock from this laptop around drizzle execute (includes network round-trip + result transfer + deserialize)`);
lines.push(`- total benchmark wall time: ${(totalWallMs / 1000).toFixed(1)}s`);
lines.push("");
lines.push("## Scenarios resolved");
lines.push("");
lines.push("| # | Org | Filter | Filtered count | Deep offset | Deep cursor |");
lines.push("|---|-----|--------|----------------|-------------|-------------|");
for (const s of scenarios) {
const count = (s as Scenario & { resolvedCount?: number }).resolvedCount;
lines.push(
`| ${s.key} | ${s.org} | \`${s.label}\` | ${count?.toLocaleString() ?? "—"} | ${s.deepOffset?.toLocaleString() ?? "—"} | ${s.deepCursor ? `\`{ t: ${s.deepCursor.t}, id: ${s.deepCursor.id.slice(0, 8)}… }\`` : "—"} |`,
);
}
lines.push("");
lines.push("## Results");
lines.push("");
lines.push(
"| # | Org | Filter | Depth | offset median ms | cursor median ms | Δ ms | offset p95 | cursor p95 | offset rows | cursor rows | offset error | cursor error |",
);
lines.push(
"|---|-----|--------|-------|------------------|------------------|------|------------|------------|-------------|-------------|--------------|--------------|",
);
for (const p of pairs) {
const off = p.offset;
const cur = p.cursor;
const delta =
off && cur && !off.error && !cur.error
? cur.medianMs - off.medianMs
: undefined;
const deltaStr =
delta === undefined
? "—"
: `${delta >= 0 ? "+" : ""}${delta.toFixed(0)}`;
lines.push(
`| ${p.scenarioKey} | ${p.org} | \`${p.scenarioLabel}\` | ${p.depth} | ${fmt(off?.medianMs)} | ${fmt(cur?.medianMs)} | ${deltaStr} | ${fmt(off?.p95Ms)} | ${fmt(cur?.p95Ms)} | ${off?.rowCount ?? "—"} | ${cur?.rowCount ?? "—"} | ${off?.error ? `\`${off.error.slice(0, 50)}\`` : ""} | ${cur?.error ? `\`${cur.error.slice(0, 50)}\`` : ""} |`,
);
}
lines.push("");
lines.push("## Raw samples (per cell)");
lines.push("");
for (const p of pairs) {
lines.push(`### ${p.scenarioKey} / ${p.depth}`);
if (p.offset) {
lines.push(
`- offset: [${p.offset.samples.map((s) => s.toFixed(0)).join(", ")}]ms${p.offset.error ? ` (error: ${p.offset.error})` : ""}`,
);
}
if (p.cursor) {
lines.push(
`- cursor: [${p.cursor.samples.map((s) => s.toFixed(0)).join(", ")}]ms${p.cursor.error ? ` (error: ${p.cursor.error})` : ""}`,
);
}
lines.push("");
}
return lines.join("\n");
};
const redactHost = (url: string | undefined): string => {
if (!url) return "<unset>";
try {
const u = new URL(url);
return `${u.hostname}:${u.port || "5432"}`;
} catch {
return "<unparseable>";
}
};
const main = async () => {
const startedAt = performance.now();
console.log(
chalk.magentaBright(
"\n================ Pagination Benchmark — offset vs cursor (prod DB) ================\n",
),
);
const dbHost = redactHost(process.env.DATABASE_URL);
console.log(chalk.cyan(`db host: ${dbHost}`));
const { db, client } = initDrizzle();
try {
console.log(chalk.cyan("Resolving Firecrawl internal_ids for IN-list cell..."));
const firecrawlInternalIds = await resolveFirecrawlInternalIds({ db });
console.log(chalk.gray(` got ${firecrawlInternalIds.length} ids`));
const scenarios = buildScenarios({ firecrawlInternalIds });
// Resolve counts and deep cursors for each scenario before running cells.
for (const s of scenarios) {
process.stdout.write(chalk.gray(`Resolving count for ${s.key} (${s.label})... `));
const count = await resolveCount({ db, orgId: s.orgId, filter: s.filter });
(s as Scenario & { resolvedCount?: number }).resolvedCount = count;
console.log(chalk.gray(`${count.toLocaleString()} customers`));
if (s.withDeep) {
const deepOffset =
s.key === "01-baseline"
? FIRECRAWL_BASELINE_DEEP_OFFSET
: Math.floor((count * DEEP_OFFSET_PCT) / 100);
s.deepOffset = deepOffset;
process.stdout.write(
chalk.gray(` resolving deep cursor at offset ${deepOffset}... `),
);
try {
s.deepCursor = await resolveDeepCursor({
db,
orgId: s.orgId,
filter: s.filter,
deepOffset,
});
console.log(
chalk.gray(
`{ t: ${s.deepCursor.t}, id: ${s.deepCursor.id.slice(0, 8)}… }`,
),
);
} catch (err) {
console.log(
chalk.yellow(
`failed: ${err instanceof Error ? err.message : String(err)}`,
),
);
s.withDeep = false;
}
}
}
const cells = scenarios.flatMap(buildCellsForScenario);
console.log();
console.log(chalk.cyan(`Running ${cells.length} cells × ${REPEATS} repeats...`));
console.log();
const results: CellResult[] = [];
for (let i = 0; i < cells.length; i++) {
const cell = cells[i];
process.stdout.write(
chalk.gray(
`[${(i + 1).toString().padStart(2)}/${cells.length}] ${cell.scenarioKey} ${cell.queryShape} ${cell.depth} ... `,
),
);
const result = await measureCell({ db, cell });
results.push(result);
if (result.error) {
console.log(chalk.red(`error: ${result.error.slice(0, 80)}`));
} else {
console.log(
chalk.green(
`median=${result.medianMs.toFixed(0)}ms p95=${result.p95Ms.toFixed(0)}ms rows=${result.rowCount}`,
),
);
}
}
const pairs = pairResults(results);
const totalWallMs = performance.now() - startedAt;
const report = renderReport({ scenarios, pairs, totalWallMs, dbHost });
const date = new Date().toISOString().slice(0, 10);
const outPath = join(RESULTS_DIR, `${date}-offset-vs-cursor.md`);
writeFileSync(outPath, report);
console.log();
console.log(chalk.green(`✅ Report written to ${outPath}`));
console.log(
chalk.magentaBright(
`\n================ Benchmark Complete (${(totalWallMs / 1000).toFixed(1)}s) ================\n`,
),
);
} catch (error) {
console.error(chalk.red("\n❌ Benchmark failed:"));
if (error instanceof Error) {
console.error(chalk.red(` ${error.message}`));
console.error(chalk.gray(error.stack));
} else {
console.error(chalk.red(` ${String(error)}`));
}
process.exit(1);
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,109 @@
# Pagination Benchmark — offset vs cursor — 2026-05-13
## Config
- db host: `aws-us-east-2-2.pg.psdb.cloud:6432`
- env: `live`
- limit: 1000
- repeats per cell: 1
- statement_timeout_ms: 60000
- read_only: true
- shared opts: withSubs=true, includeInvoices=false, withEntities=false, withTrialsUsed=false, cusProductLimit=15
- timings are wall-clock from this laptop around drizzle execute (includes network round-trip + result transfer + deserialize)
- total benchmark wall time: 218.3s
## Scenarios resolved
| # | Org | Filter | Filtered count | Deep offset | Deep cursor |
|---|-----|--------|----------------|-------------|-------------|
| 01-baseline | firecrawl | `none (baseline)` | 1,225,211 | 950,000 | `{ t: 1774210364093, id: 5ee7a1eb… }` |
| 02-search-gmail | firecrawl | `search '@gmail'` | 184,264 | 82,918 | `{ t: 1776593058654, id: c0e7d692… }` |
| 03-status-active | firecrawl | `inStatuses=['active']` | 1,225,211 | 551,344 | `{ t: 1774237999733, id: 95fdf38e… }` |
| 04-plan-massive | firecrawl | `plans=['free']` | 1,206,690 | 543,010 | `{ t: 1774238574871, id: 281784e4… }` |
| 05-plan-mid | firecrawl | `plans=['hobby']` | 27,421 | 12,339 | `{ t: 1774200253978, id: 5845392c… }` |
| 06-plan-rare | firecrawl | `plans=['scale_monthly']` | 204 | — | — |
| 07-processor-stripe | firecrawl | `processors=['stripe']` | 38,933 | 17,519 | `{ t: 1773503945904, id: 7e4ae8d2… }` |
| 08-internal-ids | firecrawl | `internalCustomerIds=[10]` | 10 | — | — |
| 09-processor-revenuecat | runable | `processors=['revenuecat']` | 1,274 | — | — |
## Results
| # | Org | Filter | Depth | offset median ms | cursor median ms | Δ ms | offset p95 | cursor p95 | offset rows | cursor rows | offset error | cursor error |
|---|-----|--------|-------|------------------|------------------|------|------------|------------|-------------|-------------|--------------|--------------|
| 01-baseline | firecrawl | `none (baseline)` | page1 | 3440 | 3393 | -47 | 3440 | 3393 | 1000 | 1001 | | |
| 01-baseline | firecrawl | `none (baseline)` | deep | 4126 | 2956 | -1169 | 4126 | 2956 | 1000 | 1001 | | |
| 02-search-gmail | firecrawl | `search '@gmail'` | page1 | 2924 | 2964 | +41 | 2924 | 2964 | 1000 | 1001 | | |
| 02-search-gmail | firecrawl | `search '@gmail'` | deep | 3393 | 3751 | +358 | 3393 | 3751 | 1000 | 1001 | | |
| 03-status-active | firecrawl | `inStatuses=['active']` | page1 | 3939 | 4185 | +246 | 3939 | 4185 | 1000 | 1001 | | |
| 03-status-active | firecrawl | `inStatuses=['active']` | deep | 7306 | 3746 | -3560 | 7306 | 3746 | 1000 | 1001 | | |
| 04-plan-massive | firecrawl | `plans=['free']` | page1 | 2676 | 2903 | +227 | 2676 | 2903 | 1000 | 1001 | | |
| 04-plan-massive | firecrawl | `plans=['free']` | deep | 36372 | 1784 | -34588 | 36372 | 1784 | 1000 | 1001 | | |
| 05-plan-mid | firecrawl | `plans=['hobby']` | page1 | 5539 | 7062 | +1523 | 5539 | 7062 | 1000 | 1001 | | |
| 05-plan-mid | firecrawl | `plans=['hobby']` | deep | 38772 | 4632 | -34140 | 38772 | 4632 | 1000 | 1001 | | |
| 06-plan-rare | firecrawl | `plans=['scale_monthly']` | page1 | 899 | 877 | -23 | 899 | 877 | 139 | 139 | | |
| 07-processor-stripe | firecrawl | `processors=['stripe']` | page1 | 2850 | 3017 | +167 | 2850 | 3017 | 1000 | 1001 | | |
| 07-processor-stripe | firecrawl | `processors=['stripe']` | deep | 8627 | 4797 | -3829 | 8627 | 4797 | 1000 | 1001 | | |
| 08-internal-ids | firecrawl | `internalCustomerIds=[10]` | page1 | 467 | 472 | +5 | 467 | 472 | 10 | 10 | | |
| 09-processor-revenuecat | runable | `processors=['revenuecat']` | page1 | 6261 | 5212 | -1049 | 6261 | 5212 | 1000 | 1001 | | |
## Raw samples (per cell)
### 01-baseline / page1
- offset: [3440]ms
- cursor: [3393]ms
### 01-baseline / deep
- offset: [4126]ms
- cursor: [2956]ms
### 02-search-gmail / page1
- offset: [2924]ms
- cursor: [2964]ms
### 02-search-gmail / deep
- offset: [3393]ms
- cursor: [3751]ms
### 03-status-active / page1
- offset: [3939]ms
- cursor: [4185]ms
### 03-status-active / deep
- offset: [7306]ms
- cursor: [3746]ms
### 04-plan-massive / page1
- offset: [2676]ms
- cursor: [2903]ms
### 04-plan-massive / deep
- offset: [36372]ms
- cursor: [1784]ms
### 05-plan-mid / page1
- offset: [5539]ms
- cursor: [7062]ms
### 05-plan-mid / deep
- offset: [38772]ms
- cursor: [4632]ms
### 06-plan-rare / page1
- offset: [899]ms
- cursor: [877]ms
### 07-processor-stripe / page1
- offset: [2850]ms
- cursor: [3017]ms
### 07-processor-stripe / deep
- offset: [8627]ms
- cursor: [4797]ms
### 08-internal-ids / page1
- offset: [467]ms
- cursor: [472]ms
### 09-processor-revenuecat / page1
- offset: [6261]ms
- cursor: [5212]ms

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,304 @@
import { AppEnv } from "@autumn/shared";
import chalk from "chalk";
import { sql, type SQL } from "drizzle-orm";
import { RELEVANT_STATUSES } from "../src/internal/customers/cusProducts/CusProductService";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
import { getCursorPaginatedFullCusQuery } from "../src/internal/customers/cursorPaginatedFullCusQuery";
import { getOptimizedFullCusQuery } from "./optimizedFullCusQuery";
loadLocalEnv();
const ORG_ID = "org_2sWv2S8LJ9iaTjLI6UtNsfL88Kt";
const ENV: AppEnv = AppEnv.Sandbox;
const REPEATS = 5;
const STATEMENT_TIMEOUT_MS = 60_000;
const DEEP_OFFSET_PCT = parseInt(process.env.OFFSET_PCT ?? "60", 10);
const LIMIT = parseInt(process.env.LIMIT ?? "1000", 10);
const CUS_PRODUCT_LIMIT = 15;
const SHOW_EXPLAIN = process.env.EXPLAIN !== "false";
const SKIP_CURRENT = process.env.SKIP_CURRENT === "true";
const SKIP_OPTIMIZED = process.env.SKIP_OPTIMIZED === "true";
const DASHBOARD_MODE = process.env.DASHBOARD === "true";
type DB = ReturnType<typeof initDrizzle>["db"];
const normalizeRows = (r: unknown): Record<string, unknown>[] => {
if (Array.isArray(r)) return r as Record<string, unknown>[];
if (r && typeof r === "object" && "rows" in r) {
return (r as { rows: Record<string, unknown>[] }).rows;
}
return [];
};
const runInTxn = async ({ db, query }: { db: DB; query: SQL }) => {
return db.transaction(async (tx) => {
await tx.execute(
sql.raw(`SET LOCAL statement_timeout = ${STATEMENT_TIMEOUT_MS}`),
);
await tx.execute(sql.raw("SET LOCAL transaction_read_only = on"));
return normalizeRows(await tx.execute(query));
});
};
const resolveTotalCount = async ({ db }: { db: DB }) => {
const result = await runInTxn({
db,
query: sql`
SELECT COUNT(*)::int AS total_count
FROM customers c
WHERE c.org_id = ${ORG_ID} AND c.env = ${ENV}
`,
});
return (result[0] as { total_count: number }).total_count;
};
const resolveDeepCursor = async ({
db,
offset,
}: {
db: DB;
offset: number;
}) => {
const result = await runInTxn({
db,
query: sql`
SELECT c.created_at, c.id
FROM customers c
WHERE c.org_id = ${ORG_ID} AND c.env = ${ENV}
ORDER BY c.created_at DESC, c.id DESC
LIMIT 1 OFFSET ${offset}
`,
});
const row = result[0] as { created_at: number; id: string } | undefined;
if (!row) throw new Error(`No customer at offset ${offset}`);
return { v: 0 as const, t: row.created_at, id: row.id };
};
const buildQuery = (
cursor?: { v: 0; t: number; id: string },
variant: "current" | "optimized" = "current",
internalCustomerIds?: string[],
): SQL => {
const builder =
variant === "optimized"
? getOptimizedFullCusQuery
: getCursorPaginatedFullCusQuery;
return builder({
orgId: ORG_ID,
env: ENV,
inStatuses: RELEVANT_STATUSES,
withSubs: true,
limit: internalCustomerIds?.length ?? LIMIT,
cursor,
internalCustomerIds,
cusProductLimit: CUS_PRODUCT_LIMIT,
});
};
const resolveInternalIds = async ({
db,
offset,
limit,
}: {
db: DB;
offset: number;
limit: number;
}): Promise<string[]> => {
const result = await runInTxn({
db,
query: sql`
SELECT c.internal_id
FROM customers c
WHERE c.org_id = ${ORG_ID} AND c.env = ${ENV}
ORDER BY c.created_at DESC, c.id DESC
LIMIT ${limit} OFFSET ${offset}
`,
});
return (result as unknown as { internal_id: string }[]).map(
(r) => r.internal_id,
);
};
const measureRun = async ({
db,
cursor,
label,
variant = "current",
internalCustomerIds,
}: {
db: DB;
cursor?: { v: 0; t: number; id: string };
label: string;
variant?: "current" | "optimized";
internalCustomerIds?: string[];
}) => {
const samples: number[] = [];
for (let i = 0; i < REPEATS; i++) {
const t0 = performance.now();
await runInTxn({ db, query: buildQuery(cursor, variant, internalCustomerIds) });
const ms = performance.now() - t0;
samples.push(ms);
process.stdout.write(chalk.gray(` run ${i + 1}/${REPEATS}: ${ms.toFixed(0)}ms\n`));
}
const sorted = [...samples].sort((a, b) => a - b);
const median = sorted[Math.floor(sorted.length / 2)] ?? 0;
const p95 = sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95))] ?? 0;
const min = sorted[0] ?? 0;
const max = sorted[sorted.length - 1] ?? 0;
console.log(
chalk.bold(
` ${label}: median=${median.toFixed(0)}ms p95=${p95.toFixed(0)}ms min=${min.toFixed(0)}ms max=${max.toFixed(0)}ms`,
),
);
return { median, p95, min, max, samples };
};
const runExplain = async ({
db,
cursor,
variant = "current",
internalCustomerIds,
}: {
db: DB;
cursor?: { v: 0; t: number; id: string };
variant?: "current" | "optimized";
internalCustomerIds?: string[];
}) => {
const explain = await runInTxn({
db,
query: sql`EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) ${buildQuery(cursor, variant, internalCustomerIds)}`,
});
return explain.map((r) => r["QUERY PLAN"]).join("\n");
};
const main = async () => {
console.log(
chalk.magentaBright(
`\n================ SQL Bench — unit-test-org ================\n`,
),
);
const { db, client } = initDrizzle();
try {
console.log(chalk.cyan(`Org: ${ORG_ID} Env: ${ENV} Limit: ${LIMIT}`));
console.log(chalk.cyan("Resolving total customer count..."));
const total = await resolveTotalCount({ db });
const deepOffset = Math.floor((total * DEEP_OFFSET_PCT) / 100);
console.log(
chalk.gray(
` total=${total.toLocaleString()} deep_offset(${DEEP_OFFSET_PCT}%)=${deepOffset.toLocaleString()}`,
),
);
console.log(chalk.cyan(`Resolving deep cursor at offset ${deepOffset}...`));
const deepCursor = await resolveDeepCursor({ db, offset: deepOffset });
console.log(
chalk.gray(` cursor = { t: ${deepCursor.t}, id: ${deepCursor.id} }\n`),
);
let curFirst: { median: number } | null = null;
let curDeep: { median: number } | null = null;
let optFirst: { median: number } | null = null;
let optDeep: { median: number } | null = null;
let dashIds: string[] | undefined;
if (DASHBOARD_MODE) {
const offset = Math.floor((total * DEEP_OFFSET_PCT) / 100);
console.log(
chalk.cyan(`Dashboard mode: resolving ${LIMIT} internal_ids at offset ${offset}...`),
);
dashIds = await resolveInternalIds({ db, offset, limit: LIMIT });
console.log(chalk.gray(` got ${dashIds.length} ids\n`));
}
if (!SKIP_CURRENT) {
console.log(chalk.bold("→ CURRENT first page:"));
curFirst = await measureRun({ db, label: "current first" });
console.log(chalk.bold(`→ CURRENT deep page${DASHBOARD_MODE ? " (internalCustomerIds)" : ""}:`));
curDeep = await measureRun({
db,
cursor: DASHBOARD_MODE ? undefined : deepCursor,
internalCustomerIds: DASHBOARD_MODE ? dashIds : undefined,
label: "current deep",
});
} else {
console.log(chalk.gray("(SKIP_CURRENT=true — skipping current variant)"));
}
if (!SKIP_OPTIMIZED) {
console.log();
console.log(chalk.bold("→ OPTIMIZED first page:"));
optFirst = await measureRun({
db,
label: "optim first",
variant: "optimized",
});
console.log(chalk.bold(`→ OPTIMIZED deep page${DASHBOARD_MODE ? " (internalCustomerIds)" : ""}:`));
optDeep = await measureRun({
db,
cursor: DASHBOARD_MODE ? undefined : deepCursor,
internalCustomerIds: DASHBOARD_MODE ? dashIds : undefined,
label: "optim deep",
variant: "optimized",
});
} else {
console.log(chalk.gray("(SKIP_OPTIMIZED=true — skipping optimized variant)"));
}
if (SHOW_EXPLAIN) {
if (!SKIP_CURRENT) {
console.log();
console.log(
chalk.magenta("================ EXPLAIN: CURRENT deep ================"),
);
console.log(await runExplain({ db, cursor: deepCursor }));
}
if (!SKIP_OPTIMIZED) {
console.log();
console.log(
chalk.magenta(
"================ EXPLAIN: OPTIMIZED deep ================",
),
);
console.log(
await runExplain({ db, cursor: deepCursor, variant: "optimized" }),
);
}
}
console.log();
console.log(chalk.magentaBright("================ Summary ================"));
const fmtDelta = (oldMs: number, newMs: number) => {
const delta = ((newMs - oldMs) / oldMs) * 100;
const arrow = delta < 0 ? "↓" : "↑";
return chalk[delta < 0 ? "green" : "red"](
`${arrow}${Math.abs(delta).toFixed(0)}%`,
);
};
if (curFirst && optFirst) {
console.log(
` first page current=${curFirst.median.toFixed(0)}ms optimized=${optFirst.median.toFixed(0)}ms ${fmtDelta(curFirst.median, optFirst.median)}`,
);
console.log(
` deep page current=${curDeep!.median.toFixed(0)}ms optimized=${optDeep!.median.toFixed(0)}ms ${fmtDelta(curDeep!.median, optDeep!.median)}`,
);
} else if (curFirst) {
console.log(` first page current=${curFirst.median.toFixed(0)}ms`);
console.log(` deep page current=${curDeep!.median.toFixed(0)}ms`);
} else if (optFirst) {
console.log(` first page optimized=${optFirst.median.toFixed(0)}ms`);
console.log(` deep page optimized=${optDeep!.median.toFixed(0)}ms`);
}
} catch (err) {
console.error(chalk.red(`\n❌ ${err instanceof Error ? err.message : err}`));
if (err instanceof Error && err.stack) console.error(chalk.gray(err.stack));
process.exit(1);
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,463 @@
import chalk from "chalk";
import { sql, type SQL } from "drizzle-orm";
import { writeFileSync } from "node:fs";
import { join } from "node:path";
import { initDrizzle } from "../src/db/initDrizzle";
import { loadLocalEnv } from "../src/utils/envUtils";
loadLocalEnv();
const ORG_ID = "biu9vSF7vghBLSKW1UTDwxHBAivjnPaK";
const ENV = "live";
const LABEL = "firecrawl-deep";
const LIMIT = 1000;
const FETCH_LIMIT = LIMIT + 1;
const SQL_REPEATS = 1;
const REASSEMBLY_REPEATS = 20;
const STATEMENT_TIMEOUT_MS = 30_000;
const DEEP_CURSOR = {
t: 1774237983361,
id: "772c9569-fc97-4c30-9fd8-c8a585b66755",
};
const RESULTS_DIR = join(import.meta.dir, "results");
type DB = ReturnType<typeof initDrizzle>["db"];
const buildVariant07Sql = (): SQL => sql`
WITH cr AS MATERIALIZED (
SELECT
c.internal_id,
c.id,
c.created_at,
row_to_json(c) AS row_json
FROM customers c
WHERE c.org_id = ${ORG_ID}
AND c.env = ${ENV}
AND (c.created_at, c.id) < (${DEEP_CURSOR.t}, ${DEEP_CURSOR.id})
ORDER BY c.created_at DESC, c.id DESC
LIMIT ${FETCH_LIMIT}
),
cps_flat AS MATERIALIZED (
SELECT
cp.id,
cp.internal_customer_id,
cp.internal_product_id,
cp.free_trial_id,
cp.subscription_ids,
(row_to_json(cp)::jsonb || jsonb_build_object('product', row_to_json(prod)))::json AS row_json
FROM cr
JOIN LATERAL (
SELECT cp.*
FROM customer_products cp
WHERE cp.internal_customer_id = cr.internal_id
AND cp.status = ANY(ARRAY['active', 'past_due', 'scheduled'])
ORDER BY cp.created_at DESC
LIMIT 15
) cp ON true
JOIN products prod ON cp.internal_product_id = prod.internal_id
),
ces_combined AS MATERIALIZED (
SELECT 'bound'::text AS kind, ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cps_flat
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.customer_product_id = cps_flat.id
) ce ON true
UNION ALL
SELECT 'loose'::text AS kind, ce.id, ce.entitlement_id, row_to_json(ce) AS row_json
FROM cr
JOIN LATERAL (
SELECT ce.*
FROM customer_entitlements ce
WHERE ce.internal_customer_id = cr.internal_id
AND ce.customer_product_id IS NULL
AND (ce.expires_at IS NULL OR ce.expires_at > EXTRACT(EPOCH FROM now()) * 1000)
ORDER BY ce.id DESC
LIMIT 30
) ce ON true
),
arrays AS MATERIALIZED (
SELECT
(SELECT array_agg(id) FROM ces_combined) AS all_ce_ids,
(SELECT array_agg(DISTINCT entitlement_id) FROM ces_combined) AS distinct_entitlement_ids,
(SELECT array_agg(DISTINCT free_trial_id) FILTER (WHERE free_trial_id IS NOT NULL) FROM cps_flat) AS free_trial_ids
)
SELECT
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cr) AS customers,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM cps_flat) AS customer_products,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_combined WHERE kind = 'bound') AS customer_entitlements,
(SELECT COALESCE(json_agg(row_json), '[]'::json) FROM ces_combined WHERE kind = 'loose') AS extra_customer_entitlements,
(SELECT COALESCE(json_agg(row_to_json(cpr)::jsonb || jsonb_build_object('price', row_to_json(p))), '[]'::json)
FROM cps_flat cps
JOIN LATERAL (SELECT cpr.* FROM customer_prices cpr WHERE cpr.customer_product_id = cps.id) cpr ON true
LEFT JOIN LATERAL (SELECT p.* FROM prices p WHERE p.id = cpr.price_id) p ON true) AS customer_prices,
(SELECT COALESCE(json_agg(row_to_json(e)::jsonb || jsonb_build_object('feature', row_to_json(f))), '[]'::json)
FROM unnest((SELECT distinct_entitlement_ids FROM arrays)) AS u(entitlement_id)
JOIN LATERAL (SELECT e.* FROM entitlements e WHERE e.id = u.entitlement_id) e ON true
JOIN LATERAL (SELECT f.* FROM features f WHERE f.internal_id = e.internal_feature_id) f ON true) AS entitlements,
(SELECT COALESCE(json_agg(row_to_json(ro)), '[]'::json)
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (SELECT ro.* FROM rollovers ro WHERE ro.cus_ent_id = u.ce_id AND (ro.expires_at IS NULL OR ro.expires_at > EXTRACT(EPOCH FROM now()) * 1000)) ro ON true) AS rollovers,
(SELECT COALESCE(json_agg(row_to_json(r)), '[]'::json)
FROM unnest((SELECT all_ce_ids FROM arrays)) AS u(ce_id)
JOIN LATERAL (SELECT r.* FROM replaceables r WHERE r.cus_ent_id = u.ce_id) r ON true) AS replaceables,
(SELECT COALESCE(json_agg(row_to_json(ft)), '[]'::json)
FROM unnest((SELECT free_trial_ids FROM arrays)) AS u(ft_id)
JOIN LATERAL (SELECT ft.* FROM free_trials ft WHERE ft.id = u.ft_id) ft ON true) AS free_trials,
(SELECT COALESCE(json_agg(row_to_json(s)), '[]'::json)
FROM (
SELECT DISTINCT s.*
FROM cps_flat cps
CROSS JOIN LATERAL unnest(cps.subscription_ids) AS sub_id_t(sub_id)
JOIN LATERAL (SELECT s.* FROM subscriptions s WHERE s.stripe_id = sub_id_t.sub_id) s ON true
WHERE cps.subscription_ids IS NOT NULL
) s) AS subscriptions
`;
type V07Row = {
customers: any[];
customer_products: any[];
customer_entitlements: any[];
extra_customer_entitlements: any[];
customer_prices: any[];
entitlements: any[];
rollovers: any[];
replaceables: any[];
free_trials: any[];
subscriptions: any[];
};
const reassemble = (flat: V07Row) => {
const {
customers,
customer_products,
customer_entitlements,
extra_customer_entitlements,
customer_prices,
entitlements,
rollovers,
replaceables,
free_trials,
subscriptions,
} = flat;
const entById = new Map<string, any>();
for (const e of entitlements) entById.set(e.id, e);
const ftById = new Map<string, any>();
for (const ft of free_trials) ftById.set(ft.id, ft);
const subByStripeId = new Map<string, any>();
for (const s of subscriptions) subByStripeId.set(s.stripe_id, s);
const rolloversByCeId = new Map<string, any[]>();
for (const ro of rollovers) {
const list = rolloversByCeId.get(ro.cus_ent_id);
if (list) list.push(ro);
else rolloversByCeId.set(ro.cus_ent_id, [ro]);
}
const replaceablesByCeId = new Map<string, any[]>();
for (const r of replaceables) {
const list = replaceablesByCeId.get(r.cus_ent_id);
if (list) list.push(r);
else replaceablesByCeId.set(r.cus_ent_id, [r]);
}
const cpricesByCpId = new Map<string, any[]>();
for (const cpr of customer_prices) {
const list = cpricesByCpId.get(cpr.customer_product_id);
if (list) list.push(cpr);
else cpricesByCpId.set(cpr.customer_product_id, [cpr]);
}
const hydrateCe = (ce: any) => ({
...ce,
entitlement: entById.get(ce.entitlement_id) ?? null,
rollovers: rolloversByCeId.get(ce.id) ?? [],
replaceables: replaceablesByCeId.get(ce.id) ?? [],
});
const cesByCpId = new Map<string, any[]>();
for (const ce of customer_entitlements) {
const hydrated = hydrateCe(ce);
const list = cesByCpId.get(ce.customer_product_id);
if (list) list.push(hydrated);
else cesByCpId.set(ce.customer_product_id, [hydrated]);
}
const looseCesByCusId = new Map<string, any[]>();
for (const ce of extra_customer_entitlements) {
const hydrated = hydrateCe(ce);
const list = looseCesByCusId.get(ce.internal_customer_id);
if (list) list.push(hydrated);
else looseCesByCusId.set(ce.internal_customer_id, [hydrated]);
}
const cpsByCusId = new Map<string, any[]>();
for (const cp of customer_products) {
const hydrated = {
...cp,
customer_prices: cpricesByCpId.get(cp.id) ?? [],
customer_entitlements: cesByCpId.get(cp.id) ?? [],
free_trial: cp.free_trial_id ? (ftById.get(cp.free_trial_id) ?? null) : null,
};
const list = cpsByCusId.get(cp.internal_customer_id);
if (list) list.push(hydrated);
else cpsByCusId.set(cp.internal_customer_id, [hydrated]);
}
const subsByCusId = new Map<string, any[]>();
for (const cp of customer_products) {
if (!cp.subscription_ids?.length) continue;
const existing = subsByCusId.get(cp.internal_customer_id) ?? [];
const seen = new Set(existing.map((s: any) => s.stripe_id));
for (const subId of cp.subscription_ids) {
if (seen.has(subId)) continue;
const sub = subByStripeId.get(subId);
if (sub) {
existing.push(sub);
seen.add(subId);
}
}
if (existing.length) subsByCusId.set(cp.internal_customer_id, existing);
}
const result: any[] = [];
for (const c of customers) {
result.push({
...c,
customer_products: cpsByCusId.get(c.internal_id) ?? [],
extra_customer_entitlements: looseCesByCusId.get(c.internal_id) ?? [],
subscriptions: subsByCusId.get(c.internal_id) ?? [],
});
}
return result;
};
const runQueryInTxn = async ({
db,
query,
}: {
db: DB;
query: SQL;
}): Promise<Record<string, unknown>[]> => {
return await db.transaction(async (tx) => {
await tx.execute(
sql.raw(`SET LOCAL statement_timeout = ${STATEMENT_TIMEOUT_MS}`),
);
await tx.execute(sql.raw("SET LOCAL transaction_read_only = on"));
const result = await tx.execute(query);
return result as unknown as Record<string, unknown>[];
});
};
const summarise = (samples: number[]) => {
const sorted = [...samples].sort((a, b) => a - b);
return {
min: sorted[0] ?? 0,
median: sorted[Math.floor(sorted.length / 2)] ?? 0,
p95: sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95))] ?? 0,
max: sorted[sorted.length - 1] ?? 0,
samples: sorted,
};
};
const main = async () => {
console.log(
chalk.magentaBright(
`\n================ Variant 07 + Reassembly Benchmark — ${LABEL} ================\n`,
),
);
const { db, client } = initDrizzle();
try {
console.log(chalk.cyan(`Org: ${ORG_ID} (${ENV})`));
console.log(
chalk.cyan(
`Deep cursor: t=${DEEP_CURSOR.t} id=${DEEP_CURSOR.id} limit=${LIMIT}\n`,
),
);
// Step 1 — EXPLAIN ANALYZE pass for server-side SQL execution time
console.log(chalk.cyan("[1/3] EXPLAIN (ANALYZE, FORMAT JSON) — server-side ms"));
const explainSamples: number[] = [];
let lastExplainPlan: any = null;
for (let i = 0; i < SQL_REPEATS; i++) {
const explainRows = await runQueryInTxn({
db,
query: sql`EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) ${buildVariant07Sql()}`,
});
const plan = (explainRows[0] as { "QUERY PLAN": any })["QUERY PLAN"];
const planObj = Array.isArray(plan) ? plan[0] : plan;
const execTime = planObj["Execution Time"] as number;
explainSamples.push(execTime);
lastExplainPlan = planObj;
process.stdout.write(chalk.gray(` run ${i + 1}: ${execTime.toFixed(2)}ms\n`));
}
const sqlSummary = summarise(explainSamples);
// Step 2 — actual query to capture rows for reassembly
console.log(chalk.cyan("\n[2/3] Executing variant 07 to capture row payload"));
const queryStart = performance.now();
const rows = await runQueryInTxn({ db, query: buildVariant07Sql() });
const queryWallMs = performance.now() - queryStart;
const flatRow = rows[0] as unknown as V07Row;
const counts = {
customers: flatRow.customers?.length ?? 0,
customer_products: flatRow.customer_products?.length ?? 0,
customer_entitlements: flatRow.customer_entitlements?.length ?? 0,
extra_customer_entitlements: flatRow.extra_customer_entitlements?.length ?? 0,
customer_prices: flatRow.customer_prices?.length ?? 0,
entitlements: flatRow.entitlements?.length ?? 0,
rollovers: flatRow.rollovers?.length ?? 0,
replaceables: flatRow.replaceables?.length ?? 0,
free_trials: flatRow.free_trials?.length ?? 0,
subscriptions: flatRow.subscriptions?.length ?? 0,
};
console.log(
chalk.gray(` client-side wall (incl. UK→US network): ${queryWallMs.toFixed(2)}ms`),
);
console.log(chalk.gray(` row counts: ${JSON.stringify(counts)}`));
const payloadBytes = Buffer.byteLength(JSON.stringify(flatRow), "utf8");
console.log(
chalk.gray(` payload size: ${(payloadBytes / 1024 / 1024).toFixed(2)} MB`),
);
// Step 3 — reassembly benchmark (pure JS, in-memory)
console.log(
chalk.cyan(`\n[3/3] Reassembly benchmark — ${REASSEMBLY_REPEATS} runs`),
);
// Warm up the JIT
for (let i = 0; i < 3; i++) reassemble(flatRow);
const reassemblySamples: number[] = [];
let lastReassembledLen = 0;
for (let i = 0; i < REASSEMBLY_REPEATS; i++) {
const start = performance.now();
const reassembled = reassemble(flatRow);
const elapsed = performance.now() - start;
reassemblySamples.push(elapsed);
lastReassembledLen = reassembled.length;
}
const reassemblySummary = summarise(reassemblySamples);
console.log(
chalk.gray(
` reassembled ${lastReassembledLen} FullCustomers (${REASSEMBLY_REPEATS} runs)`,
),
);
// Report
console.log(chalk.magentaBright("\n================ RESULTS ================\n"));
console.log(chalk.bold("SQL (server-side, EXPLAIN ANALYZE Execution Time):"));
console.log(
` min=${sqlSummary.min.toFixed(2)}ms median=${sqlSummary.median.toFixed(2)}ms p95=${sqlSummary.p95.toFixed(2)}ms max=${sqlSummary.max.toFixed(2)}ms`,
);
console.log(chalk.gray(` samples: ${sqlSummary.samples.map((s) => s.toFixed(1)).join(", ")}`));
console.log();
console.log(chalk.bold("Reassembly (JS, in-memory, network-free):"));
console.log(
` min=${reassemblySummary.min.toFixed(2)}ms median=${reassemblySummary.median.toFixed(2)}ms p95=${reassemblySummary.p95.toFixed(2)}ms max=${reassemblySummary.max.toFixed(2)}ms`,
);
console.log(chalk.gray(` samples: ${reassemblySummary.samples.map((s) => s.toFixed(2)).join(", ")}`));
console.log();
console.log(chalk.bold.green("Total (network-free) median:"));
console.log(
chalk.bold.green(
` ${(sqlSummary.median + reassemblySummary.median).toFixed(2)}ms = ${sqlSummary.median.toFixed(2)}ms SQL + ${reassemblySummary.median.toFixed(2)}ms reassembly`,
),
);
console.log();
console.log(chalk.bold("Reference (UK→US client wall, includes ~100ms network):"));
console.log(` one-shot db.execute: ${queryWallMs.toFixed(2)}ms`);
console.log();
const date = new Date().toISOString().slice(0, 10);
const reportPath = join(RESULTS_DIR, `${date}-v07-reassembly-${LABEL}.md`);
const fixturePath = join(RESULTS_DIR, `${date}-v07-fixture-${LABEL}.json`);
const lines: string[] = [];
lines.push(`# Variant 07 + JS Reassembly — ${date}${LABEL}`);
lines.push("");
lines.push("## Config");
lines.push(`- org_id: \`${ORG_ID}\``);
lines.push(`- env: \`${ENV}\``);
lines.push(`- limit: ${LIMIT} (fetch ${FETCH_LIMIT})`);
lines.push(`- deep cursor: \`{ t: ${DEEP_CURSOR.t}, id: ${DEEP_CURSOR.id} }\``);
lines.push(`- SQL repeats: ${SQL_REPEATS}`);
lines.push(`- reassembly repeats: ${REASSEMBLY_REPEATS} (after 3 warmup runs)`);
lines.push("");
lines.push("## SQL (server-side, EXPLAIN ANALYZE Execution Time, network-free)");
lines.push("");
lines.push(`| min | median | p95 | max |`);
lines.push(`|---|---|---|---|`);
lines.push(
`| ${sqlSummary.min.toFixed(2)}ms | ${sqlSummary.median.toFixed(2)}ms | ${sqlSummary.p95.toFixed(2)}ms | ${sqlSummary.max.toFixed(2)}ms |`,
);
lines.push("");
lines.push(
`Samples: ${sqlSummary.samples.map((s) => `${s.toFixed(1)}ms`).join(", ")}`,
);
lines.push("");
lines.push("## Reassembly (JS, in-memory)");
lines.push("");
lines.push(`| min | median | p95 | max |`);
lines.push(`|---|---|---|---|`);
lines.push(
`| ${reassemblySummary.min.toFixed(2)}ms | ${reassemblySummary.median.toFixed(2)}ms | ${reassemblySummary.p95.toFixed(2)}ms | ${reassemblySummary.max.toFixed(2)}ms |`,
);
lines.push("");
lines.push(
`Samples: ${reassemblySummary.samples.map((s) => `${s.toFixed(2)}ms`).join(", ")}`,
);
lines.push("");
lines.push("## Total network-free");
lines.push("");
lines.push(
`**${(sqlSummary.median + reassemblySummary.median).toFixed(2)}ms** = ${sqlSummary.median.toFixed(2)}ms SQL + ${reassemblySummary.median.toFixed(2)}ms reassembly`,
);
lines.push("");
lines.push("## Row counts");
lines.push("");
lines.push("```json");
lines.push(JSON.stringify(counts, null, 2));
lines.push("```");
lines.push("");
lines.push(`Payload size: ${(payloadBytes / 1024 / 1024).toFixed(2)} MB`);
lines.push("");
lines.push("## Reference: UK→US client wall");
lines.push("");
lines.push(`One-shot \`db.execute\`: ${queryWallMs.toFixed(2)}ms`);
lines.push("");
lines.push("## Last EXPLAIN plan (JSON)");
lines.push("");
lines.push("```json");
lines.push(JSON.stringify(lastExplainPlan, null, 2));
lines.push("```");
writeFileSync(reportPath, lines.join("\n"));
writeFileSync(fixturePath, JSON.stringify(flatRow));
console.log(chalk.green(`✅ Report written to ${reportPath}`));
console.log(chalk.green(`✅ Fixture written to ${fixturePath}`));
console.log(
chalk.magentaBright(
"\n================ Benchmark Complete ================\n",
),
);
} catch (error) {
console.error(chalk.red("\n❌ Benchmark failed:"));
console.error(error);
console.error(chalk.gray(JSON.stringify(error, Object.getOwnPropertyNames(error || {}))));
process.exit(1);
} finally {
await client.end();
process.exit(0);
}
};
await main();

View File

@@ -0,0 +1,547 @@
import {
AffectedResource,
AllowanceType,
type ApiCustomerV5,
ApiVersion,
ApiVersionClass,
applyResponseVersionChanges,
AppEnv,
BillingInterval,
CollectionMethod,
type CustomerLegacyData,
CusProductStatus,
EntInterval,
FeatureType,
type FullCustomer,
type FullCustomerEntitlement,
type FullCusProduct
} from "@autumn/shared";
import chalk from "chalk";
import { getApiCustomerBase } from "../src/internal/customers/cusUtils/apiCusUtils/getApiCustomerBase";
const CUSTOMER_COUNT = 1000;
const ITERATIONS = 5;
const WARMUP_ITERATIONS = 2;
const ORG_ID = "org_bench";
const FEATURE_IDS = [
"messages",
"credits",
"users",
"projects",
"api_calls",
"storage_gb",
"connectors",
"webhooks",
"exports",
"dashboards",
];
const ADDON_FEATURE_IDS = [
"extra_messages",
"extra_credits",
"premium_support",
"sso",
"audit_log",
];
const LOOSE_FEATURE_IDS = [
"loose_a",
"loose_b",
"loose_c",
"loose_d",
"loose_e",
];
const featureFromId = (id: string) => ({
internal_id: `fe_${id}`,
org_id: ORG_ID,
created_at: 1000,
env: AppEnv.Sandbox,
id,
name: id,
type: FeatureType.Metered,
config: { usage_type: "single_use" },
display: { singular: id, plural: `${id}s` },
archived: false,
event_names: [id],
});
const allFeatures = [
...FEATURE_IDS.map(featureFromId),
...ADDON_FEATURE_IDS.map(featureFromId),
...LOOSE_FEATURE_IDS.map(featureFromId),
];
const makeEntitlement = ({
cusEntId,
productInternalId,
productCusId,
featureId,
internalCustomerId,
customerId,
}: {
cusEntId: string;
productInternalId: string;
productCusId: string | null;
featureId: string;
internalCustomerId: string;
customerId: string;
}): FullCustomerEntitlement => ({
id: cusEntId,
internal_customer_id: internalCustomerId,
internal_entity_id: null,
internal_feature_id: `fe_${featureId}`,
customer_id: customerId,
feature_id: featureId,
customer_product_id: productCusId,
entitlement_id: `ent_${featureId}_${productInternalId}`,
created_at: 1000,
unlimited: false,
balance: 100,
additional_balance: 0,
usage_allowed: null,
next_reset_at: 2000,
adjustment: 0,
expires_at: null,
cache_version: 0,
entities: null,
external_id: null,
entitlement: {
id: `ent_${featureId}_${productInternalId}`,
created_at: 1000,
internal_feature_id: `fe_${featureId}`,
internal_product_id: productInternalId,
is_custom: false,
allowance_type: AllowanceType.Fixed,
allowance: 100,
interval: EntInterval.Month,
interval_count: 1,
entity_feature_id: null,
feature_id: featureId,
usage_limit: null,
feature: featureFromId(featureId),
},
replaceables: [],
rollovers: [],
});
const makeCusProduct = ({
productCusId,
productInternalId,
productId,
productName,
isAddOn,
internalCustomerId,
customerId,
featureIds,
cusEntPrefix,
internalEntityId,
entityId,
}: {
productCusId: string;
productInternalId: string;
productId: string;
productName: string;
isAddOn: boolean;
internalCustomerId: string;
customerId: string;
featureIds: string[];
cusEntPrefix: string;
internalEntityId?: string | null;
entityId?: string | null;
}): FullCusProduct => ({
id: productCusId,
internal_product_id: productInternalId,
product_id: productId,
internal_customer_id: internalCustomerId,
customer_id: customerId,
internal_entity_id: internalEntityId ?? null,
entity_id: entityId ?? null,
created_at: 1500,
updated_at: null,
status: CusProductStatus.Active,
canceled: false,
starts_at: 1500,
access_starts_at: null,
trial_ends_at: null,
billing_cycle_anchor_resets_at: null,
canceled_at: null,
ended_at: null,
options: [],
free_trial_id: null,
collection_method: CollectionMethod.ChargeAutomatically,
subscription_ids: [`sub_${productCusId}`],
scheduled_ids: [],
processor: { type: "stripe" as any },
quantity: 1,
api_semver: null,
is_custom: false,
billing_version: "v2" as any,
external_id: null,
stripe_checkout_session_id: null,
customer_prices: [
{
id: `cus_price_${productCusId}`,
internal_customer_id: internalCustomerId,
customer_product_id: productCusId,
created_at: 1500,
price_id: `price_${productInternalId}`,
price: {
id: `price_${productInternalId}`,
internal_product_id: productInternalId,
org_id: ORG_ID,
created_at: 1500,
billing_type: null,
tier_behavior: null,
is_custom: false,
config: {
type: "fixed",
amount: 99,
interval: BillingInterval.Month,
} as any,
entitlement_id: null,
proration_config: null,
},
},
],
customer_entitlements: featureIds.map((fid, i) =>
makeEntitlement({
cusEntId: `${cusEntPrefix}_${i}`,
productInternalId,
productCusId,
featureId: fid,
internalCustomerId,
customerId,
}),
),
product: {
id: productId,
name: productName,
description: null,
is_add_on: isAddOn,
is_default: false,
version: 1,
group: "",
env: AppEnv.Sandbox,
internal_id: productInternalId,
org_id: ORG_ID,
created_at: 1000,
processor: { type: "stripe", id: `prod_${productId}` },
base_variant_id: null,
archived: false,
config: { ignore_past_due: false },
},
free_trial: null,
});
const makeFullCustomer = (idx: number): FullCustomer => {
const internalId = `cus_bench_${idx.toString().padStart(8, "0")}`;
const customerId = `bench_${idx}`;
const customerProducts: FullCusProduct[] = [
makeCusProduct({
productCusId: `cus_prod_main_${idx}`,
productInternalId: "prod_main",
productId: "pro",
productName: "Pro",
isAddOn: false,
internalCustomerId: internalId,
customerId,
featureIds: FEATURE_IDS,
cusEntPrefix: `cus_ent_main_${idx}`,
}),
makeCusProduct({
productCusId: `cus_prod_addon_${idx}`,
productInternalId: "prod_addon",
productId: "pro_addon",
productName: "Pro Add-on",
isAddOn: true,
internalCustomerId: internalId,
customerId,
featureIds: ADDON_FEATURE_IDS,
cusEntPrefix: `cus_ent_addon_${idx}`,
}),
];
const entities = Array.from({ length: 5 }, (_, i) => ({
id: `ent_${idx}_${i}`,
org_id: ORG_ID,
created_at: 1100,
internal_id: `ent_int_${idx}_${i}`,
internal_customer_id: internalId,
env: AppEnv.Sandbox,
name: `Entity ${i}`,
deleted: false,
feature_id: "seats",
internal_feature_id: "fe_seats",
}));
for (let i = 0; i < 3; i++) {
const ent = entities[i]!;
customerProducts.push(
makeCusProduct({
productCusId: `cus_prod_main_${idx}_e${i}`,
productInternalId: "prod_main",
productId: "pro",
productName: "Pro (Entity-scoped)",
isAddOn: false,
internalCustomerId: internalId,
customerId,
featureIds: FEATURE_IDS,
cusEntPrefix: `cus_ent_main_${idx}_e${i}`,
internalEntityId: ent.internal_id,
entityId: ent.id,
}),
);
}
const looseEnts: FullCustomerEntitlement[] = LOOSE_FEATURE_IDS.map((fid, i) =>
makeEntitlement({
cusEntId: `cus_ent_loose_${idx}_${i}`,
productInternalId: "prod_loose",
productCusId: null,
featureId: fid,
internalCustomerId: internalId,
customerId,
}),
);
return {
id: customerId,
name: `Bench Customer ${idx}`,
email: `bench+${idx}@autumn.dev`,
fingerprint: null,
internal_id: internalId,
org_id: ORG_ID,
created_at: 1000,
env: AppEnv.Sandbox,
processor: { id: `cus_stripe_${idx}`, type: "stripe" },
processors: null,
metadata: {},
send_email_receipts: false,
auto_topups: null,
spend_limits: null,
usage_alerts: null,
overage_allowed: null,
config: null,
customer_products: customerProducts,
entities,
extra_customer_entitlements: looseEnts,
subscriptions: customerProducts
.filter((cp) => cp.subscription_ids?.length)
.flatMap((cp) =>
(cp.subscription_ids ?? []).map((sid) => ({
id: sid,
stripe_id: sid,
stripe_schedule_id: null,
created_at: 1500,
usage_features: [],
metadata: {},
org_id: ORG_ID,
env: AppEnv.Sandbox,
current_period_start: 1500,
current_period_end: 4000,
})),
),
} as unknown as FullCustomer;
};
const makeCtx = () =>
({
org: {
id: ORG_ID,
slug: "bench",
created_at: 1000,
default_currency: "usd",
config: { in_statuses: [CusProductStatus.Active] },
stripe_connected: false,
},
env: AppEnv.Sandbox,
features: allFeatures,
logger: {
info: () => {},
error: () => {},
warn: () => {},
debug: () => {},
trace: () => {},
child: () => makeCtx().logger,
},
expand: [],
apiVersion: new ApiVersionClass(ApiVersion.V2_3),
}) as any;
const summarize = (samples: number[]) => {
const sorted = [...samples].sort((a, b) => a - b);
return {
min: sorted[0] ?? 0,
p50: sorted[Math.floor(sorted.length / 2)] ?? 0,
p95: sorted[Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95))] ?? 0,
max: sorted[sorted.length - 1] ?? 0,
mean: samples.reduce((a, b) => a + b, 0) / samples.length,
};
};
const fmt = (n: number) => `${n.toFixed(2)}ms`.padStart(9, " ");
const runSerial = async (customers: FullCustomer[], ctx: any) => {
const finals: ApiCustomerV5[] = [];
for (const fullCus of customers) {
const { apiCustomer: baseCustomer, legacyData } = await getApiCustomerBase({
ctx,
fullCus,
withAutumnId: false,
});
const versioned = applyResponseVersionChanges<ApiCustomerV5, CustomerLegacyData>({
input: baseCustomer,
legacyData,
targetVersion: ctx.apiVersion,
resource: AffectedResource.Customer,
ctx,
});
finals.push(versioned);
}
return finals;
};
const runPromiseAll = async (customers: FullCustomer[], ctx: any) => {
const finals = await Promise.all(
customers.map(async (fullCus) => {
const { apiCustomer: baseCustomer, legacyData } = await getApiCustomerBase({
ctx,
fullCus,
withAutumnId: false,
});
return applyResponseVersionChanges<ApiCustomerV5, CustomerLegacyData>({
input: baseCustomer,
legacyData,
targetVersion: ctx.apiVersion,
resource: AffectedResource.Customer,
ctx,
});
}),
);
return finals;
};
// "sync-equivalent" path: keeps the async function calls but uses a tight
// promise-chained sequence with no extra microtask churn between customers.
// Since getApiCustomerBase is async, true sync isn't possible without rewriting it.
const runSyncEquivalent = (customers: FullCustomer[], ctx: any) => {
let p: Promise<ApiCustomerV5[]> = Promise.resolve([] as ApiCustomerV5[]);
for (const fullCus of customers) {
p = p.then(async (acc) => {
const { apiCustomer: baseCustomer, legacyData } = await getApiCustomerBase({
ctx,
fullCus,
withAutumnId: false,
});
const versioned = applyResponseVersionChanges<ApiCustomerV5, CustomerLegacyData>({
input: baseCustomer,
legacyData,
targetVersion: ctx.apiVersion,
resource: AffectedResource.Customer,
ctx,
});
acc.push(versioned);
return acc;
});
}
return p;
};
const benchVariant = async ({
name,
customers,
ctx,
run,
}: {
name: string;
customers: FullCustomer[];
ctx: any;
run: (customers: FullCustomer[], ctx: any) => Promise<ApiCustomerV5[]>;
}) => {
for (let i = 0; i < WARMUP_ITERATIONS; i++) await run(customers, ctx);
const samples: number[] = [];
for (let i = 0; i < ITERATIONS; i++) {
const t0 = performance.now();
const result = await run(customers, ctx);
const t1 = performance.now();
if (result.length !== customers.length) {
throw new Error(`${name}: result length mismatch ${result.length} vs ${customers.length}`);
}
samples.push(t1 - t0);
}
const s = summarize(samples);
const perCustomer = s.p50 / customers.length;
console.log(
` ${chalk.cyan(name.padEnd(20))} | total p50 ${fmt(s.p50)} (per cus ${perCustomer.toFixed(3)}ms) | mean ${fmt(s.mean)} | p95 ${fmt(s.p95)} | min ${fmt(s.min)} | max ${fmt(s.max)}`,
);
return s;
};
const main = async () => {
console.log(
chalk.magentaBright(
`\n================ Version Pipeline Bench ================`,
),
);
console.log(
chalk.gray(
` customers per iter: ${CUSTOMER_COUNT.toLocaleString()}, iterations: ${ITERATIONS} (+${WARMUP_ITERATIONS} warmup)\n`,
),
);
const ctx = makeCtx();
const customers = Array.from({ length: CUSTOMER_COUNT }, (_, i) =>
makeFullCustomer(i),
);
console.log(
chalk.gray(
` shape per customer: ${customers[0]!.customer_products.length} cps · ${customers[0]!.customer_products.reduce((n, cp) => n + cp.customer_entitlements.length, 0)} bound ces · ${customers[0]!.extra_customer_entitlements.length} loose ces · ${customers[0]!.entities.length} entities`,
),
);
console.log();
console.log(chalk.bold("Baseline (serial for-await):"));
const serial = await benchVariant({ name: "serial", customers, ctx, run: runSerial });
console.log();
console.log(chalk.bold("Variant A (Promise.all):"));
const promiseAll = await benchVariant({
name: "Promise.all",
customers,
ctx,
run: runPromiseAll,
});
console.log();
console.log(chalk.bold("Variant B (sync-equivalent promise chain):"));
const syncish = await benchVariant({
name: "sync-equivalent",
customers,
ctx,
run: runSyncEquivalent,
});
const fmtDelta = (other: number, baseline: number) => {
const delta = ((other - baseline) / baseline) * 100;
const arrow = delta < 0 ? "↓" : "↑";
return `${arrow}${Math.abs(delta).toFixed(1)}%`;
};
console.log();
console.log(chalk.magentaBright("================ Summary ================"));
console.log(
` serial: ${fmt(serial.p50)} ${chalk.gray("(baseline)")}`,
);
console.log(
` Promise.all: ${fmt(promiseAll.p50)} (${fmtDelta(promiseAll.p50, serial.p50)})`,
);
console.log(
` sync-equivalent: ${fmt(syncish.p50)} (${fmtDelta(syncish.p50, serial.p50)})`,
);
};
await main();
process.exit(0);