New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Reduce the number of SQL queries #342
Conversation
I was to eager. Throwing out the externalFieldNameDependencies ended in not fetching the sub sub queries. Ok so we rather account for classicIds with
But thats just a hack. @benjie do you have a better idea? |
Subjective Evaluation: Request time cut in half 💛 |
|
I'm not sure how best to deal with rowId and I'm sure I'm getting various things from places I oughtn't since I just hacked it out as a proof of concept, so I'm awaiting Caleb's ideas on this point. |
Just discovered a bug in this relating to one-to-many relations on sub-entries on mutation payloads. |
Found it 👍 |
In this version, the |
@0x6368656174 Do you know why it doesn't work on this branch? Given it's based on the other (which didn't pass tests), I'm theorising it's because this branch pulls in the other required columns that are necessary for PostGraphQL internals, e.g. if you order by a field, that field gets implicitly added to the selection; similarly if you filter by a field. |
@benjie if I execute the query: {
allUsers {
nodes {
id
name
}
}
} In this branch, the query is selected: select coalesce(json_agg(__local_0__), '[]'::json) as "rows", ( select count(*) from ( select * from "public"."users" as __local_1__ where "id" is not null and true ) as __local_2__ ) ::integer as "totalCount", ( select count(*) from ( select * from "public"."users" as __local_1__ where "id" is not null and true ) as __local_3__ where true ) > count(*) as "hasNextPage", false as "hasPreviousPage" from ( select json_build_object( 'value', json_build_object('id', __local_4__."id", 'name', __local_4__."name"), 'cursor', json_build_array("id") ) as __local_0__ from ( select * from "public"."users" as __local_1__ where "id" is not null and true ) as __local_4__ where true and true order by "id" using < limit all ) as __local_5__ And it should be: select coalesce(json_agg(__local_0__), '[]'::json) as "rows", ( select count(*) from ( select "id", "name" from "public"."users" as __local_1__ where "id" is not null and true ) as __local_2__ ) ::integer as "totalCount", ( select count(*) from ( select "id", "name" from "public"."users" as __local_1__ where "id" is not null and true ) as __local_3__ where true ) > count(*) as "hasNextPage", false as "hasPreviousPage" from ( select json_build_object( 'value', json_build_object('id', __local_4__."id", 'name', __local_4__."name"), 'cursor', json_build_array("id") ) as __local_0__ from ( select "id", "name" from "public"."users" as __local_1__ where "id" is not null and true ) as __local_4__ where true and true order by "id" using < limit all ) as __local_5__; Plus, I do not need |
Formatted, so I can compare: SELECT coalesce(json_agg(__local_0__), '[]'::json) AS "rows",
(SELECT count(*)
FROM
(SELECT *
FROM "public"."users" AS __local_1__
WHERE "id" IS NOT NULL
AND TRUE ) AS __local_2__) ::integer AS "totalCount",
(SELECT count(*)
FROM
(SELECT *
FROM "public"."users" AS __local_1__
WHERE "id" IS NOT NULL
AND TRUE ) AS __local_3__
WHERE TRUE ) > count(*) AS "hasNextPage",
FALSE AS "hasPreviousPage"
FROM
(SELECT json_build_object('value', json_build_object('id', __local_4__."id", 'name', __local_4__."name"), 'cursor', json_build_array("id")) AS __local_0__
FROM
(SELECT *
FROM "public"."users" AS __local_1__
WHERE "id" IS NOT NULL
AND TRUE ) AS __local_4__
WHERE TRUE
AND TRUE
ORDER BY "id" USING <
LIMIT ALL) AS __local_5__ SELECT coalesce(json_agg(__local_0__), '[]'::json) AS "rows",
(SELECT count(*)
FROM
(SELECT "id",
"name"
FROM "public"."users" AS __local_1__
WHERE "id" IS NOT NULL
AND TRUE ) AS __local_2__) ::integer AS "totalCount",
(SELECT count(*)
FROM
(SELECT "id",
"name"
FROM "public"."users" AS __local_1__
WHERE "id" IS NOT NULL
AND TRUE ) AS __local_3__
WHERE TRUE ) > count(*) AS "hasNextPage",
FALSE AS "hasPreviousPage"
FROM
(SELECT json_build_object('value', json_build_object('id', __local_4__."id", 'name', __local_4__."name"), 'cursor', json_build_array("id")) AS __local_0__
FROM
(SELECT "id",
"name"
FROM "public"."users" AS __local_1__
WHERE "id" IS NOT NULL
AND TRUE ) AS __local_4__
WHERE TRUE
AND TRUE
ORDER BY "id" USING <
LIMIT ALL) AS __local_5__; |
@0x6368656174 So you're saying that the I'm aware that we over-fetch the hasPreviousPage/etc - I ran out of time whilst writing this proof of concept. The intention of this PR was performance, rather than excluding fields for permissions reasons, and I'm hesitant to advance the code any further knowing that we'll probably be rebuilding a fair chunk of it. That said, you're welcome to build your own branch off of this one that solves your issue - if it's simple enough then I may consider merging, but you'll have to be careful to include all required fields, not just the ones that are directly requested (because PostGraphQL requires some internally for various things: sorting, relations, etc). Personally I don't use column-level grants on select statements, I just split the tables based on permissions boundaries into sub-tables, e.g. instead of a monolithic |
@benjie Splitting one monolithic table into several is not a way out of the problem. First, there can be too many small tables that will degrade performance. Secondly, if one column is available for two user roles, but the rest are not available, then you get a whole table with only one column. |
@benjie The easiest solution is to replace the |
Well, for the counts simply I don't find performance degrades too much with splitting concerns into separate tables; one-to-one indexed joins are very fast. |
This code: Needs to specify |
There's also an issue here: If you have a procedure which returns a row from the database, this isn't sufficient to parse it into a Map as is required by much of the postgraphql internals - it just leaves it as a vanilla JSON object. If you then try and access attributes on this, it throws an error like |
Using |
Seems this same issue was fixed on master only a couple months ago. |
Closing in favour of V4: #506 |
TODO:
KNOWN ISSUES:
I've been informed by @cusxio that the following query returns null, but that including the
username
field fixes this - sounds like I need to addusername
to the list of implicit fields on the search endpoints:Workaround:
Fixes #219
Fixes #265