Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oMZjU-0001fh-MX for pgsql-performance@arkaria.postgresql.org; Fri, 12 Aug 2022 18:50:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1oMZjR-00021T-K7 for pgsql-performance@arkaria.postgresql.org; Fri, 12 Aug 2022 18:50:05 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oMZjR-00021I-7g for pgsql-performance@lists.postgresql.org; Fri, 12 Aug 2022 18:50:05 +0000 Received: from mout02.posteo.de ([185.67.36.66]) by magus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1oMZjN-0005l8-BW for pgsql-performance@lists.postgresql.org; Fri, 12 Aug 2022 18:50:04 +0000 Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id 73810240103 for ; Fri, 12 Aug 2022 20:49:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.de; s=2017; t=1660330199; bh=UHNKKf+CFeeJk5T0JpYjwWBq+X33Wo+9QvIJdoYYBUA=; h=Date:To:From:Subject:From; b=KuWf9sQwZoHMKi1S8+TNKj+0k3JAoOCoKspniUhC3Tkarm1XhIRg9BXtkom+vZZpF Yl49htippyd7sqwRmTg7t1b7Lm0/ibr+s6z1tr7CjPBsh9Z3pZNqAhmHiPi7BnMYVp vTi2VsXfPa+ndcHAkMssTFdVlrcuEgOY8KgmvPOGxgKOyB6Nzr+edty7tdIhrJrb6C pNwar56jkee30mkitK+IOdB11Dv/0Bf6QB/ce0ZEI9yadSLvWWh4VOg/hbyDSOjCgI k0Hr9+HlcRAcQhJu2SbRZmH2aDceGga4Z6GDLezGJaeKtp++1oLbVfTtmUh5N0QMni wuF6q/SG9x2+w== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4M4CQt4nKVz9rxN for ; Fri, 12 Aug 2022 20:49:58 +0200 (CEST) Message-ID: <1eac0b83-217d-94d2-cde2-db74ae3fbe86@posteo.de> Date: Fri, 12 Aug 2022 18:49:58 +0000 MIME-Version: 1.0 To: pgsql-performance@lists.postgresql.org From: Nico Heller Subject: to_jsonb performance on array aggregated correlated subqueries Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk Good day, consider the following query: WITH aggregation(     SELECT            a.*,           (SELECT array_agg(b.*) FROM b WHERE b.a_id = a.id) as "bs",           (SELECT array_agg(c.*) FROM c WHERE c.a_id = a.id) as "cs",           (SELECT array_agg(d.*) FROM d WHERE d.a_id = a.id) as "ds",           (SELECT array_agg(e.*) FROM d WHERE e.a_id = a.id) as "es"     FROM a WHERE a.id IN ( 1000 queries / sec). Furthermore the CPU usage is quite high. Is there anything I could improve? I am open for other solutions but I am wondering if I ran into an edge case of "to_jsonb" for "anonymous records" (these are just rows without a defined UDT) - this is just a wild guess though. I am mostly looking to decrease the load (CPU and memory) on Postgres itself. Furthermore I would like to know why the memory usage is so significant. Any tips on how to analyze this issue are appreciated as well -  my knowledge is limited to being average at interpreting EXPLAIN ANALYZE results. Here's a succinct list of the why's, what I have found out so far and solution I already tried/ don't want to consider: - LEFT JOINing potentially creates a huge resultset because of the cartesian product, thats a nono - not using "to_jsonb" is sadly also not possible as Postgres' array + record syntax is very unfriendly and hard to parse (it's barely documented if at all and the quoting rules are cumbersome, furthermore I lack column names in the array which would make the parsing sensitive to future table changes and thus cumbersome to maintain) in my application - I know I could solve this with a separate query for a,b,c,d and e while "joinining" the result in my application, but I am looking for another way to do this (bear with me, treat this as an academic question :)) - I am using "to_jsonb" to simply map the result to my data model via a json mapper - EXPLAIN ANALYZE is not showing anything special when using "to_jsonb" vs. not using it, the outermost (hash) join just takes more time - is there a more granular EXPLAIN that shows me the runtime of functions like "to_jsonb"? - I tried an approach where b,c,d,e where array columns of UDTs: UDTs are not well supported by my application stack (JDBC) and are generally undesireable for me (because of a lack of migration possibilities) - I don't want to duplicate my data into another table (e.g. that has jsonb columns) - MATERIALIZED VIEWS are also undesirable as the manual update, its update is non-incremental which would make a refresh on a big data set take a long time - split the query into chunks to reduce the IN()-statement list size makes no measurable difference - I don't want to use JSONB columns for b,c,d and e because future changes of b,c,d or e's structure (e.g. new fields, changing a datatype) are harder to achieve with JSONB and it lacks constraint checks on insert (e.g. not null on column b.xy) Kind regards and thank you for your time, Nico Heller P.S: Sorry for the long list of "I don't want to do this", some of them are not possible because of other requirements