Skip to content

Commit d3a2daa

Browse files
committed
Performance improvements
1 parent 2403c17 commit d3a2daa

13 files changed

Lines changed: 199 additions & 153 deletions

apps/backend/src/lib/bulldozer/db/index.perf.test.ts

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,15 @@ const IS_CI = (() => {
2121
const cursorAgent = Reflect.get(env, "CURSOR_AGENT");
2222
return (ci === true || ci === "true" || ci === "1") && (cursorAgent !== true && cursorAgent !== 'true' && cursorAgent !== "1");
2323
})();
24-
const DEFAULT_LOAD_ROW_COUNT = IS_CI ? 200_000 : 20_000;
24+
const DEFAULT_LOAD_ROW_COUNT = IS_CI ? 200_000 : 20_0000;
2525
const LOAD_PREFILL_MAX_MS = 30_000;
2626
const LOAD_COUNT_QUERY_MAX_MS = 5_000;
2727
const LOAD_POINT_MUTATION_MAX_MS = 400;
2828
const LOAD_SET_ROW_AVG_ITERATIONS = 10;
2929
const LOAD_SET_ROW_AVG_MAX_MS = 50;
30+
const LOAD_ONLINE_MUTATION_MAX_MS = 50;
31+
const LOAD_SUBSET_ITERATION_MAX_MS = 50;
32+
const LOAD_SUBSET_ITERATION_ROW_COUNT = 1_000;
3033
const LOAD_TABLE_DELETE_MAX_MS = 20_000;
3134
const LOAD_DERIVED_INIT_MAX_MS = 90_000;
3235
const LOAD_DERIVED_COUNT_QUERY_MAX_MS = 10_000;
@@ -121,9 +124,10 @@ describe.sequential("bulldozer db performance (real postgres)", () => {
121124
const dbName = dbUrls.full.replace(/^.*\//, "").replace(/\?.*$/, "");
122125
const adminSql = postgres(dbUrls.base, { onnotice: () => undefined });
123126
const sql = postgres(dbUrls.full, { onnotice: () => undefined, max: 1 });
127+
const PERF_STATEMENT_TIMEOUT = "180s";
124128

125129
async function runStatements(statements: SqlStatement[]) {
126-
await sql.unsafe(toExecutableSqlTransaction(statements));
130+
await sql.unsafe(toExecutableSqlTransaction(statements, { statementTimeout: PERF_STATEMENT_TIMEOUT }));
127131
}
128132

129133
async function readRows(query: SqlQuery) {
@@ -515,6 +519,18 @@ describe.sequential("bulldozer db performance (real postgres)", () => {
515519
const setRowAverageMs = setRowIterationTimes.reduce((acc, value) => acc + value, 0) / setRowIterationTimes.length;
516520
logLine(`[bulldozer-perf] load setRow average (${LOAD_SET_ROW_AVG_ITERATIONS} iterations): ${setRowAverageMs.toFixed(1)} ms`);
517521
expect(setRowAverageMs).toBeLessThanOrEqual(LOAD_SET_ROW_AVG_MAX_MS);
522+
const onlineInsert = await measureMs("load online setRow insert (stored table)", async () => {
523+
await runStatements(table.setRow("perf-online-row", expr(jsonbLiteral({ team: "beta", value: 111 }))));
524+
});
525+
expect(onlineInsert.elapsedMs).toBeLessThanOrEqual(LOAD_ONLINE_MUTATION_MAX_MS);
526+
const onlineUpdate = await measureMs("load online setRow update (stored table)", async () => {
527+
await runStatements(table.setRow("perf-online-row", expr(jsonbLiteral({ team: "beta", value: 222 }))));
528+
});
529+
expect(onlineUpdate.elapsedMs).toBeLessThanOrEqual(LOAD_ONLINE_MUTATION_MAX_MS);
530+
const onlineDelete = await measureMs("load online deleteRow (stored table)", async () => {
531+
await runStatements(table.deleteRow("perf-online-row"));
532+
});
533+
expect(onlineDelete.elapsedMs).toBeLessThanOrEqual(LOAD_ONLINE_MUTATION_MAX_MS);
518534

519535
const pointDelete = await measureMs("load point delete (deleteRow existing)", async () => {
520536
await runStatements(table.deleteRow(`seed-${Math.floor(loadRowCount / 2) - 1}`));
@@ -818,6 +834,21 @@ describe.sequential("bulldozer db performance (real postgres)", () => {
818834
expect(filteredDeltaRows.map((row) => ({ rowIdentifier: row.rowidentifier, rowData: row.rowdata }))).toEqual([
819835
{ rowIdentifier: "seed-100000:1", rowData: { team: "delta", value: 999 } },
820836
]);
837+
const groupedSubsetFromStart = await measureMs(`load iterate groupedByTeam subset from start (${LOAD_SUBSET_ITERATION_ROW_COUNT} rows)`, async () => {
838+
return await sql.unsafe(`
839+
SELECT *
840+
FROM (${toQueryableSqlQuery(groupedByTeam.listRowsInGroup({
841+
groupKey: expr(`to_jsonb('beta'::text)`),
842+
start: "start",
843+
end: "end",
844+
startInclusive: true,
845+
endInclusive: true,
846+
}))}) AS "rows"
847+
LIMIT ${LOAD_SUBSET_ITERATION_ROW_COUNT}
848+
`);
849+
});
850+
expect(groupedSubsetFromStart.elapsedMs).toBeLessThanOrEqual(LOAD_SUBSET_ITERATION_MAX_MS);
851+
expect(groupedSubsetFromStart.result).toHaveLength(LOAD_SUBSET_ITERATION_ROW_COUNT);
821852
const sortedHighValueByTeam = declareSortTable({
822853
tableId: "load-prefilled-users-high-value-sorted",
823854
fromTable: filteredHighValue,
@@ -845,6 +876,36 @@ describe.sequential("bulldozer db performance (real postgres)", () => {
845876
await runStatements(sortedHighValueByTeam.init());
846877
});
847878
expect(sortInit.elapsedMs).toBeLessThan(LOAD_SORT_TABLE_INIT_MAX_MS);
879+
const sortedSubsetFromStart = await measureMs(`load iterate sortedHighValueByTeam subset from start (${LOAD_SUBSET_ITERATION_ROW_COUNT} rows)`, async () => {
880+
return await sql.unsafe(`
881+
SELECT *
882+
FROM (${toQueryableSqlQuery(sortedHighValueByTeam.listRowsInGroup({
883+
groupKey: expr(`to_jsonb('beta'::text)`),
884+
start: "start",
885+
end: expr(`to_jsonb(719::int)`),
886+
startInclusive: true,
887+
endInclusive: true,
888+
}))}) AS "rows"
889+
LIMIT ${LOAD_SUBSET_ITERATION_ROW_COUNT}
890+
`);
891+
});
892+
expect(sortedSubsetFromStart.elapsedMs).toBeLessThanOrEqual(LOAD_SUBSET_ITERATION_MAX_MS);
893+
expect(sortedSubsetFromStart.result).toHaveLength(LOAD_SUBSET_ITERATION_ROW_COUNT);
894+
const sortedSubsetFromSortKey = await measureMs(`load iterate sortedHighValueByTeam subset from sort-key cursor (${LOAD_SUBSET_ITERATION_ROW_COUNT} rows)`, async () => {
895+
return await sql.unsafe(`
896+
SELECT *
897+
FROM (${toQueryableSqlQuery(sortedHighValueByTeam.listRowsInGroup({
898+
groupKey: expr(`to_jsonb('beta'::text)`),
899+
start: expr(`to_jsonb(900::int)`),
900+
end: expr(`to_jsonb(919::int)`),
901+
startInclusive: true,
902+
endInclusive: true,
903+
}))}) AS "rows"
904+
LIMIT ${LOAD_SUBSET_ITERATION_ROW_COUNT}
905+
`);
906+
});
907+
expect(sortedSubsetFromSortKey.elapsedMs).toBeLessThanOrEqual(LOAD_SUBSET_ITERATION_MAX_MS);
908+
expect(sortedSubsetFromSortKey.result).toHaveLength(LOAD_SUBSET_ITERATION_ROW_COUNT);
848909
const lFoldInit = await measureMs("load init foldedHighValueByTeam", async () => {
849910
await runStatements(foldedHighValueByTeam.init());
850911
});
@@ -941,7 +1002,6 @@ describe.sequential("bulldozer db performance (real postgres)", () => {
9411002
},
9421003
},
9431004
]);
944-
9451005
const bulkDelete = await measureMs("load full table delete", async () => {
9461006
await runStatements(table.delete());
9471007
});
@@ -960,7 +1020,7 @@ describe.sequential("bulldozer db performance (real postgres)", () => {
9601020
`;
9611021
expect(isInitializedRows[0].initialized).toBe(false);
9621022

963-
logLine(`[bulldozer-perf] load thresholds(ms): prefill<=${LOAD_PREFILL_MAX_MS}, baseCount<=${LOAD_COUNT_QUERY_MAX_MS}, setRowAvg<=${LOAD_SET_ROW_AVG_MAX_MS} over ${LOAD_SET_ROW_AVG_ITERATIONS}, pointDelete<=${LOAD_POINT_MUTATION_MAX_MS}, derivedInit<=${LOAD_DERIVED_INIT_MAX_MS}, filterInit<=${LOAD_FILTER_TABLE_INIT_MAX_MS}, sortInit<=${LOAD_SORT_TABLE_INIT_MAX_MS}, lfoldInit<=${LOAD_LFOLD_TABLE_INIT_MAX_MS}, leftJoinInit<=${LOAD_LEFT_JOIN_TABLE_INIT_MAX_MS}, concatInit<=${LOAD_CONCAT_TABLE_INIT_MAX_MS}, limitInit<=${LOAD_LIMIT_TABLE_INIT_MAX_MS}, expandingInit<=${LOAD_EXPANDING_INIT_MAX_MS}, derivedCount<=${LOAD_DERIVED_COUNT_QUERY_MAX_MS}, filterCount<=${LOAD_FILTER_TABLE_COUNT_QUERY_MAX_MS}, lfoldCount<=${LOAD_LFOLD_TABLE_COUNT_QUERY_MAX_MS}, leftJoinCount<=${LOAD_LEFT_JOIN_TABLE_COUNT_QUERY_MAX_MS}, concatCount<=${LOAD_CONCAT_TABLE_COUNT_QUERY_MAX_MS}, limitCount<=${LOAD_LIMIT_TABLE_COUNT_QUERY_MAX_MS}, expandingCount<=${LOAD_EXPANDING_COUNT_QUERY_MAX_MS}, filteredQuery<=${LOAD_FILTERED_QUERY_MAX_MS}, tableDelete<=${LOAD_TABLE_DELETE_MAX_MS}`);
964-
}, 180_000);
1023+
logLine(`[bulldozer-perf] load thresholds(ms): prefill<=${LOAD_PREFILL_MAX_MS}, baseCount<=${LOAD_COUNT_QUERY_MAX_MS}, setRowAvg<=${LOAD_SET_ROW_AVG_MAX_MS} over ${LOAD_SET_ROW_AVG_ITERATIONS}, pointDelete<=${LOAD_POINT_MUTATION_MAX_MS}, onlineMutation<=${LOAD_ONLINE_MUTATION_MAX_MS}, subsetIteration<=${LOAD_SUBSET_ITERATION_MAX_MS} for ${LOAD_SUBSET_ITERATION_ROW_COUNT} rows, derivedInit<=${LOAD_DERIVED_INIT_MAX_MS}, filterInit<=${LOAD_FILTER_TABLE_INIT_MAX_MS}, sortInit<=${LOAD_SORT_TABLE_INIT_MAX_MS}, lfoldInit<=${LOAD_LFOLD_TABLE_INIT_MAX_MS}, leftJoinInit<=${LOAD_LEFT_JOIN_TABLE_INIT_MAX_MS}, concatInit<=${LOAD_CONCAT_TABLE_INIT_MAX_MS}, limitInit<=${LOAD_LIMIT_TABLE_INIT_MAX_MS}, expandingInit<=${LOAD_EXPANDING_INIT_MAX_MS}, derivedCount<=${LOAD_DERIVED_COUNT_QUERY_MAX_MS}, filterCount<=${LOAD_FILTER_TABLE_COUNT_QUERY_MAX_MS}, lfoldCount<=${LOAD_LFOLD_TABLE_COUNT_QUERY_MAX_MS}, leftJoinCount<=${LOAD_LEFT_JOIN_TABLE_COUNT_QUERY_MAX_MS}, concatCount<=${LOAD_CONCAT_TABLE_COUNT_QUERY_MAX_MS}, limitCount<=${LOAD_LIMIT_TABLE_COUNT_QUERY_MAX_MS}, expandingCount<=${LOAD_EXPANDING_COUNT_QUERY_MAX_MS}, filteredQuery<=${LOAD_FILTERED_QUERY_MAX_MS}, tableDelete<=${LOAD_TABLE_DELETE_MAX_MS}`);
1024+
}, 300_000);
9651025
});
9661026

apps/backend/src/lib/bulldozer/db/index.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ export type Table<GK extends Json, SK extends Json, RD extends RowData> = {
3535
registerRowChangeTrigger(trigger: (changesTable: SqlExpression<{ __brand: "$SQL_Table" }>) => SqlStatement[]): { deregister: () => void },
3636
};
3737

38-
export { declareStoredTable } from "./tables/stored-table";
39-
export { declareGroupByTable } from "./tables/group-by-table";
40-
export { declareFlatMapTable } from "./tables/flat-map-table";
41-
export { declareMapTable } from "./tables/map-table";
42-
export { declareFilterTable } from "./tables/filter-table";
43-
export { declareLimitTable } from "./tables/limit-table";
4438
export { declareConcatTable } from "./tables/concat-table";
45-
export { declareSortTable } from "./tables/sort-table";
39+
export { declareFilterTable } from "./tables/filter-table";
40+
export { declareFlatMapTable } from "./tables/flat-map-table";
41+
export { declareGroupByTable } from "./tables/group-by-table";
4642
export { declareLFoldTable } from "./tables/l-fold-table";
4743
export { declareLeftJoinTable } from "./tables/left-join-table";
44+
export { declareLimitTable } from "./tables/limit-table";
45+
export { declareMapTable } from "./tables/map-table";
46+
export { declareSortTable } from "./tables/sort-table";
47+
export { declareStoredTable } from "./tables/stored-table";
4848

4949
const BULLDOZER_LOCK_ID = 7857391; // random number to avoid conflicts with other applications
5050

@@ -85,11 +85,12 @@ export function toExecutableSqlStatements(statements: SqlStatement[]): string {
8585
${executableStatements}
8686
`;
8787
}
88-
export function toExecutableSqlTransaction(statements: SqlStatement[]): string {
88+
export function toExecutableSqlTransaction(statements: SqlStatement[], options: { statementTimeout?: string } = {}): string {
8989
return deindent`
9090
BEGIN;
9191
9292
SET LOCAL jit = off;
93+
${options.statementTimeout ? `SET LOCAL statement_timeout = '${options.statementTimeout}';` : ""}
9394
9495
SELECT pg_advisory_xact_lock(${BULLDOZER_LOCK_ID});
9596

apps/backend/src/lib/bulldozer/db/table-type.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

apps/backend/src/lib/bulldozer/db/tables/concat-table.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { StackAssertionError } from "@stackframe/stack-shared/dist/utils/errors";
21
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
2+
import { StackAssertionError } from "@stackframe/stack-shared/dist/utils/errors";
33
import { deindent } from "@stackframe/stack-shared/dist/utils/strings";
4+
import type { Table } from "..";
45
import type { Json, RowData, RowIdentifier, SqlExpression, SqlStatement, TableId } from "../utilities";
56
import {
67
getStorageEnginePath,
@@ -9,14 +10,13 @@ import {
910
quoteSqlIdentifier,
1011
quoteSqlJsonbLiteral,
1112
quoteSqlStringLiteral,
13+
singleNullSortKeyRangePredicate,
1214
sqlArray,
1315
sqlExpression,
1416
sqlQuery,
1517
sqlStatement,
16-
singleNullSortKeyRangePredicate,
1718
tableIdToDebugString,
1819
} from "../utilities";
19-
import type { Table } from "../table-type";
2020

2121
export function declareConcatTable<
2222
GK extends Json,

apps/backend/src/lib/bulldozer/db/tables/filter-table.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,18 @@
1-
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
21
import { pick } from "@stackframe/stack-shared/dist/utils/objects";
3-
import type { Json, RowData, RowIdentifier, SqlExpression, SqlMapper, SqlPredicate, SqlStatement, TableId } from "../utilities";
2+
import type { Table } from "..";
3+
import type { Json, RowData, SqlPredicate, TableId } from "../utilities";
44
import {
5-
getStorageEnginePath,
6-
getTablePath,
7-
getTablePathSegments,
8-
quoteSqlIdentifier,
9-
quoteSqlJsonbLiteral,
10-
quoteSqlStringLiteral,
11-
sqlArray,
12-
sqlExpression,
13-
sqlMapper,
14-
sqlPredicate,
15-
sqlQuery,
16-
sqlStatement,
17-
singleNullSortKeyRangePredicate,
18-
tableIdToDebugString,
5+
getStorageEnginePath,
6+
getTablePath,
7+
getTablePathSegments,
8+
quoteSqlJsonbLiteral,
9+
sqlArray,
10+
sqlExpression,
11+
sqlMapper,
12+
sqlStatement,
13+
tableIdToDebugString
1914
} from "../utilities";
2015
import { declareFlatMapTable } from "./flat-map-table";
21-
import type { Table } from "../table-type";
2216

2317
export function declareFilterTable<
2418
GK extends Json,

apps/backend/src/lib/bulldozer/db/tables/flat-map-table.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
2+
import type { Table } from "..";
23
import type { Json, RowData, RowIdentifier, SqlExpression, SqlMapper, SqlStatement, TableId } from "../utilities";
34
import {
4-
getStorageEnginePath,
5-
getTablePath,
6-
quoteSqlIdentifier,
7-
quoteSqlStringLiteral,
8-
sqlExpression,
9-
sqlQuery,
10-
sqlStatement,
11-
singleNullSortKeyRangePredicate,
12-
tableIdToDebugString,
5+
getStorageEnginePath,
6+
getTablePath,
7+
quoteSqlIdentifier,
8+
singleNullSortKeyRangePredicate,
9+
sqlExpression,
10+
sqlQuery,
11+
sqlStatement,
12+
tableIdToDebugString
1313
} from "../utilities";
14-
import type { Table } from "../table-type";
1514

1615
export function declareFlatMapTable<
1716
GK extends Json,

apps/backend/src/lib/bulldozer/db/tables/group-by-table.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
2+
import type { Table } from "..";
23
import type { Json, RowData, RowIdentifier, SqlExpression, SqlMapper, SqlStatement, TableId } from "../utilities";
34
import {
4-
getStorageEnginePath,
5-
getTablePath,
6-
quoteSqlIdentifier,
7-
quoteSqlStringLiteral,
8-
sqlExpression,
9-
sqlQuery,
10-
sqlStatement,
11-
singleNullSortKeyRangePredicate,
12-
tableIdToDebugString,
5+
getStorageEnginePath,
6+
getTablePath,
7+
quoteSqlIdentifier,
8+
singleNullSortKeyRangePredicate,
9+
sqlExpression,
10+
sqlQuery,
11+
sqlStatement,
12+
tableIdToDebugString
1313
} from "../utilities";
14-
import type { Table } from "../table-type";
1514

1615
export function declareGroupByTable<
1716
GK extends Json,

apps/backend/src/lib/bulldozer/db/tables/l-fold-table.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto";
2+
import type { Table } from "..";
23
import type { Json, RowData, RowIdentifier, SqlExpression, SqlMapper, SqlStatement, TableId } from "../utilities";
34
import {
45
getStorageEnginePath,
56
getTablePath,
67
getTablePathSegments,
78
quoteSqlIdentifier,
89
quoteSqlJsonbLiteral,
9-
quoteSqlStringLiteral,
1010
sqlArray,
1111
sqlExpression,
1212
sqlMapper,
1313
sqlQuery,
1414
sqlStatement,
15-
singleNullSortKeyRangePredicate,
16-
tableIdToDebugString,
15+
tableIdToDebugString
1716
} from "../utilities";
18-
import type { Table } from "../table-type";
1917
import { declareSortTable } from "./sort-table";
2018

2119
/**
@@ -53,12 +51,17 @@ export function declareLFoldTable<
5351
reducer: SqlMapper<{ oldState: S, oldRowData: OldRD }, { newState: S, newRowsData: NewRD[] }>,
5452
}): Table<GK, SK, NewRD> {
5553
const triggers = new Map<string, (changesTable: SqlExpression<{ __brand: "$SQL_Table" }>) => SqlStatement[]>();
56-
const sourceSortTableId: TableId = {
54+
const fromTableOperator = (
55+
"operator" in options.fromTable.debugArgs
56+
&& typeof options.fromTable.debugArgs.operator === "string"
57+
) ? options.fromTable.debugArgs.operator : null;
58+
const reusesInputSortTable = fromTableOperator === "sort";
59+
const sourceSortTableId: TableId = reusesInputSortTable ? options.fromTable.tableId : {
5760
tableType: "internal",
5861
internalId: "lfold-source-sort",
5962
parent: options.tableId,
6063
};
61-
const sourceSortTable = declareSortTable({
64+
const sourceSortTable: Table<GK, SK, OldRD> = reusesInputSortTable ? options.fromTable : declareSortTable({
6265
tableId: sourceSortTableId,
6366
fromTable: options.fromTable,
6467
getSortKey: sqlMapper`
@@ -496,10 +499,11 @@ export function declareLFoldTable<
496499
(gen_random_uuid(), ${groupsPath}, 'null'::jsonb),
497500
(gen_random_uuid(), ${getStorageEnginePath(options.tableId, ["metadata"])}, '{ "version": 1 }'::jsonb)
498501
`,
499-
...sourceSortTable.init(),
502+
...(reusesInputSortTable ? [] : sourceSortTable.init()),
500503
sqlQuery`
501504
SELECT
502505
"groupPath"."keyPath"[cardinality("groupPath"."keyPath")] AS "groupKey",
506+
("groupPath"."keyPath"[cardinality("groupPath"."keyPath")]::text) AS "groupKeyText",
503507
("sourceRows"."keyPath"[cardinality("sourceRows"."keyPath")] #>> '{}') AS "rowIdentifier",
504508
"sourceRows"."value"->'rowSortKey' AS "rowSortKey",
505509
"sourceRows"."value"->'rowData' AS "rowData",
@@ -516,6 +520,7 @@ export function declareLFoldTable<
516520
sqlQuery`
517521
SELECT
518522
"sourceRows"."groupKey" AS "groupKey",
523+
"sourceRows"."groupKeyText" AS "groupKeyText",
519524
"sourceRows"."rowIdentifier" AS "rowIdentifier",
520525
"sourceRows"."rowSortKey" AS "rowSortKey",
521526
"sourceRows"."rowData" AS "rowData",
@@ -528,6 +533,7 @@ export function declareLFoldTable<
528533
WITH RECURSIVE "recomputedRows" AS (
529534
SELECT
530535
"firstRows"."groupKey" AS "groupKey",
536+
"firstRows"."groupKeyText" AS "groupKeyText",
531537
"firstRows"."rowIdentifier" AS "rowIdentifier",
532538
"firstRows"."rowSortKey" AS "rowSortKey",
533539
"firstRows"."rowData" AS "rowData",
@@ -557,6 +563,7 @@ export function declareLFoldTable<
557563
558564
SELECT
559565
"nextRows"."groupKey" AS "groupKey",
566+
"nextRows"."groupKeyText" AS "groupKeyText",
560567
"nextRows"."rowIdentifier" AS "rowIdentifier",
561568
"nextRows"."rowSortKey" AS "rowSortKey",
562569
"nextRows"."rowData" AS "rowData",
@@ -566,7 +573,7 @@ export function declareLFoldTable<
566573
"reduced"."newRowsData" AS "newRowsData"
567574
FROM "recomputedRows"
568575
INNER JOIN ${quoteSqlIdentifier(allSourceRowsTableName)} AS "nextRows"
569-
ON "nextRows"."groupKey" IS NOT DISTINCT FROM "recomputedRows"."groupKey"
576+
ON "nextRows"."groupKeyText" = "recomputedRows"."groupKeyText"
570577
AND "nextRows"."rowIdentifier" = "recomputedRows"."nextRowIdentifier"
571578
CROSS JOIN LATERAL (
572579
SELECT

0 commit comments

Comments
 (0)