Re: Multiple Aggregations Order
João Haas <[email protected]> Tue, 14 Jan 2020 18:03:29 -0300
| Newsgroups | gmane.comp.db.postgresql.general |
|---|---|
| Message-ID | <CAEi5ktLYdJ0_5NTQn__7GPOi1THAM0_gRspGX5er6_G2xq_ubQ@mail.gmail.com> |
--0000000000002e01c0059c1fed19
Content-Type: text/plain; charset="UTF-8"
I'm aiming to serialize some graph data into a JSON format, and some of the
data needed for the serialization is in the relation tables, like, "this
node connects to this other node in this way". These are served to IOT
devices and the data changes a lot, so there's a ton of requests and
caching is not that efficient. Due to that, it would be ideal if I could
fetch everything in a single query, with the data needed aggregated in
arrays, so that I can denormalize them later in code (eg.:
zip(data['child_id_set'], data['child_kind_set']) in python).
Each query should have from 100~1000 items from the 'tb' table. The
amount of child relations each item has vary a lot depending on the node,
so it can be from 1~10000.
The tables themselves have some millions of rows, but I don't have access
to the production database to check how many exactly. Due to this, although
I can share the query plan, it wouldn't be so meaningful, since it is
considering my dev env, which only have ~100 rows, and it's throwing seq
scans for everything.
The query is the following:
WITH RECURSIVE tree(tree_id, tree_path) AS (
SELECT "conn"."child_id",
ARRAY["conn"."parent_id"]::integer[]
FROM "conn"
WHERE "parent_id" IN (643) -- Starting point of graph
UNION
SELECT DISTINCT ON ("conn"."child_id")
"conn"."child_id",
"tree"."tree_path" || "conn"."parent_id"
FROM "tree", "conn"
WHERE "conn"."parent_id" = "tree"."tree_id"
AND NOT "conn"."child_id" = ANY("tree"."tree_path")
) SELECT "tb".*,
array_length("tree"."tree_path", 1) AS "depth",
array_agg("conn"."child_id" ORDER BY ("conn"."order",
"conn"."kind")) FILTER (WHERE "conn"."child_id" IS NOT NULL) AS
"child_id_set",
array_agg("conn"."kind" ORDER BY ("conn"."order", "conn"."kind"))
FILTER (WHERE "conn"."child_id" IS NOT NULL) AS "child_kind_set",
array_agg("conn"."restrictions" ORDER BY ("conn"."order",
"conn"."kind")) FILTER (WHERE "conn"."child_id" IS NOT NULL) AS
"child_restrictions_set",
array_agg("conn"."meta" ORDER BY ("conn"."order", "conn"."kind"))
FILTER (WHERE "conn"."child_id" IS NOT NULL) AS "child_meta_set"
FROM "tb"
LEFT OUTER JOIN "conn"
ON "tb"."id" = "conn"."parent_id"
INNER JOIN (SELECT DISTINCT ON ("tree_id") * FROM "tree") AS "tree"
ON "tree"."tree_id" = "tb"."id"
GROUP BY "tb"."id", "tree"."tree_path";
I'm currently using Postgres 11
On Tue, Jan 14, 2020 at 4:49 PM Michael Lewis <[email protected]> wrote:
> "handle this aggregated data later in code"
>
> What is your end goal though? Also, approx how many rows in these tables?
> Can you share an example query and plan? What version are you using?
>
>>
--0000000000002e01c0059c1fed19
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div dir=3D"ltr">I'm aiming to serialize some graph da=
ta into a JSON format, and some of the data needed for the serialization is=
in the relation tables, like, "this node connects to this other node =
in this way". These are served to IOT devices and the data changes a l=
ot, so there's a ton of requests and caching is not that efficient. Due=
to that, it would be ideal if I could fetch everything in a single query, =
with the data needed aggregated in arrays, so that I can denormalize them l=
ater in code (eg.: zip(data['child_id_set'], data['child_kind_s=
et']) in python).<div><br></div><div>Each query should have from 100~10=
00 items from the 'tb' table. The amount=C2=A0of child relations ea=
ch item has vary a lot depending on the node, so it can be from 1~10000.</d=
iv><div><br></div><div>The tables themselves have some millions of rows, bu=
t I don't have access to the production database to check how many exac=
tly. Due to this, although I can share the query plan, it wouldn't be s=
o meaningful, since it is considering my dev env, which only have ~100 rows=
, and it's throwing seq scans for everything.</div><div><br></div><div>=
The query is the following:</div><font face=3D"monospace">WITH RECURSIVE tr=
ee(tree_id, tree_path) AS (<br>=C2=A0 =C2=A0 SELECT "conn"."=
child_id",<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ARRAY["con=
n"."parent_id"]::integer[]<br>=C2=A0 =C2=A0 =C2=A0 FROM &quo=
t;conn"<br>=C2=A0 =C2=A0 =C2=A0WHERE "parent_id" IN (643) --=
Starting point of graph<br>=C2=A0 =C2=A0 =C2=A0UNION<br>=C2=A0 =C2=A0 SELE=
CT DISTINCT ON ("conn"."child_id")<br>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0"conn"."child_id",<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"tree"."tree_path" ||=
"conn"."parent_id"<br>=C2=A0 =C2=A0 =C2=A0 FROM "=
tree", "conn"<br>=C2=A0 =C2=A0 =C2=A0WHERE "conn".=
"parent_id" =3D "tree"."tree_id"<br>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0AND NOT "conn"."child_id" =3D ANY(&=
quot;tree"."tree_path")<br>) SELECT "tb".*,<br>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0array_length("tree"."tree_pat=
h", 1) AS "depth",<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0arra=
y_agg("conn"."child_id" ORDER BY ("conn".&quo=
t;order", "conn"."kind")) FILTER (WHERE "conn=
"."child_id" IS NOT NULL) AS "child_id_set",<br>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0array_agg("conn"."kind&quo=
t; ORDER BY ("conn"."order", "conn"."kin=
d")) FILTER (WHERE "conn"."child_id" IS NOT NULL) =
AS "child_kind_set",<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0array_a=
gg("conn"."restrictions" ORDER BY ("conn".&qu=
ot;order", "conn"."kind")) FILTER (WHERE "con=
n"."child_id" IS NOT NULL) AS "child_restrictions_set&q=
uot;,<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0array_agg("conn"."=
;meta" ORDER BY ("conn"."order", "conn".=
"kind")) FILTER (WHERE "conn"."child_id" IS N=
OT NULL) AS "child_meta_set"<br>=C2=A0 =C2=A0 FROM "tb"=
<br>=C2=A0 =C2=A0 LEFT OUTER JOIN "conn"<br>=C2=A0 =C2=A0 =C2=A0 =
ON "tb"."id" =3D "conn"."parent_id"=
<br>=C2=A0 =C2=A0INNER JOIN (SELECT DISTINCT ON ("tree_id") * FRO=
M "tree") AS "tree"<br>=C2=A0 =C2=A0 =C2=A0 ON "tr=
ee"."tree_id" =3D "tb"."id"<br>GROUP BY =
"tb"."id", "tree"."tree_path";</fon=
t><div><font face=3D"monospace"><br></font><div>I'm currently using Pos=
tgres 11</div></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" c=
lass=3D"gmail_attr">On Tue, Jan 14, 2020 at 4:49 PM Michael Lewis <<a hr=
ef=3D"mailto:[email protected]">[email protected]</a>> wrote:<br></div=
><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border=
-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr">"h=
andle this aggregated data later in code"<div dir=3D"ltr"><br></div><d=
iv>What is your end goal though? Also, approx how many rows in these tables=
? Can you share an example query and plan? What version are you=C2=A0using?=
</div><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D=
"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-le=
ft:1ex">
</blockquote></div></div>
</blockquote></div></div>
--0000000000002e01c0059c1fed19--