Skip to content

Commit

Permalink
refactor joins to cte to improve perf
Browse files Browse the repository at this point in the history
  • Loading branch information
prostgles committed Sep 27, 2023
1 parent cba3f5b commit 9953169
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 27 deletions.
13 changes: 0 additions & 13 deletions lib/DboBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,19 +560,6 @@ export class DboBuilder {

const table = tov.name;

const makeJoin = (
isLeft = true,
filter: Parameters<JoinMaker<AnyObject>>[0],
select: Parameters<JoinMaker<AnyObject>>[1],
options: Parameters<JoinMaker<AnyObject>>[2] = {}
): ReturnType<JoinMaker<AnyObject>> => {
return {
[isLeft ? "$leftJoin" : "$innerJoin"]: options.path ?? table,
filter,
select,
... omitKeys(options, ["path"]),
}
}
this.dbo.innerJoin ??= {};
this.dbo.leftJoin ??= {};
this.dbo.innerJoinOne ??= {};
Expand Down
43 changes: 36 additions & 7 deletions lib/DboBuilder/QueryBuilder/getJoinQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ const getJoinTable = (tableName: string, pathIndex: number, isLastTableAlias: st

type GetJoinQueryResult = {
resultAlias: string;
queryLines: string[];
// queryLines: string[];
firstJoinTableJoinFields: string[];
isOrJoin: boolean;
type: "cte";
joinLines: string[];
cteLines: string[];
}

/**
Expand Down Expand Up @@ -105,30 +108,56 @@ export const getJoinQuery = (viewHandler: ViewHandler, { q1, q2, depth }: Args):
`SELECT `,
...indentLines([
...(isOrJoin? [rootTableIdField]: requiredJoinFields),
// ...requiredJoinFields,
jsonAgg,
...rootNestedSort.map(d => d.nested!.wrapperQuerySortItem)
], { appendCommas: true }),
`FROM (`,
...indentLines(innerQuery),
`) ${targetTableAlias}`,
`WHERE ${joinCondition}`,
...(isOrJoin? [
`LEFT JOIN ${q1.table} ${ROOT_TABLE_ALIAS}`,
`ON ${joinCondition}`
] : []),
// `WHERE ${joinCondition}`,
`GROUP BY ${isOrJoin? rootTableIdField : requiredJoinFields}`,
// `GROUP BY ${requiredJoinFields}`,
];

const queryLines = [
`${joinType} JOIN LATERAL (`,
// const queryLines = [
// `${joinType} JOIN LATERAL (`,
// ...indentLines(wrappingQuery),
// `) ${targetTableAlias}`,
// isOrJoin?
// `ON ${targetTableAlias}.${ROOT_TABLE_ROW_NUM_ID} = ${rootTableIdField}` :
// `ON ${joinCondition}`
// ];

/**
* This is done to prevent join cte names clashing with actual table names
*/
const targetTableAliasTempRename = asName(`${targetTableAlias}_prostgles_join_temp_rename`)
const cteLines = [
`${targetTableAliasTempRename} AS (`,
...indentLines(wrappingQuery),
`) ${targetTableAlias}`,
`)`
];

const joinLines = [
`${joinType} JOIN ( SELECT * FROM ${targetTableAliasTempRename} ) as ${targetTableAlias}`,
isOrJoin?
`ON ${targetTableAlias}.${ROOT_TABLE_ROW_NUM_ID} = ${rootTableIdField}` :
`ON ${joinCondition}`
];

return {
type: "cte",
resultAlias: JSON_AGG_FIELD_NAME,
queryLines,
// queryLines,
joinLines,
cteLines,
isOrJoin,
firstJoinTableJoinFields: firstJoinTableJoinFields,
firstJoinTableJoinFields,
}
}

Expand Down
31 changes: 29 additions & 2 deletions lib/DboBuilder/QueryBuilder/getSelectQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,43 @@ export function getSelectQuery(
const { joinAlias } = join;
return `COALESCE(${asName(joinAlias)}.${join.resultAlias}, '[]') as ${asName(joinAlias)}`
}) ?? []);

/** OR joins cannot be easily aggregated to one-many with the root table. Must group by root table id */
const hasOrJoins = parsedJoins.some(j => j.isOrJoin)

let joinCtes = !parsedJoins.length? [] : [
...parsedJoins.flatMap((j, i) => {
const needsComma = parsedJoins.length > 1 && i < parsedJoins.length -1;
return j.cteLines.concat(needsComma? [","] : []);
})
];


if(hasOrJoins){
const pkey = viewHandler.columns.find(c => c.is_pkey);
joinCtes = [
`${q.table} AS (`,
` SELECT *, ${pkey? asName(pkey.name): "ROW_NUMBER() OVER()"} as ${ROOT_TABLE_ROW_NUM_ID}`,
` FROM ${q.table}`,
`),`,
...joinCtes
]
}

if(joinCtes.length){
joinCtes.unshift(`WITH `)
}

const query = [
...joinCtes,
`SELECT`
,...indentLines(selectItems, { appendCommas: true })
, `FROM ( `
, ` SELECT * ${parsedJoins.some(j => j.isOrJoin)? `, ROW_NUMBER() OVER() as ${ROOT_TABLE_ROW_NUM_ID}` : ""}`
, ` SELECT *`
, ` FROM ${q.table}`
, ...(q.where? [` ${q.where}`] : [])
, `) ${ROOT_TABLE_ALIAS}`
, ...parsedJoins.flatMap(j => j.queryLines)
, ...parsedJoins.flatMap(j => j.joinLines)
, ...getRootGroupBy(q, selectParamsGroupBy)
, ...prepareOrderByQuery(q.orderByItems)
, ...(q.having ? [`HAVING ${q.having} `] : [])
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prostgles-server",
"version": "4.1.65",
"version": "4.1.66",
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion tests/client/PID.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
291834
482784
2 changes: 1 addition & 1 deletion tests/server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9953169

Please sign in to comment.