On Sun, Nov 14, 2021 at 9:07 AM Alvaro Herrera <alvhe...@alvh.no-ip.org> wrote:
> On 2021-Nov-11, Alvaro Herrera wrote: > > > But what really surprised me is that the the average time to optimize > > per function is now 2.06ms ... less than half of the previous > > measurement. It emits 10% less functions than before, but the time to > > both optimize and emit is reduced by 50%. How does that make sense? > > Ah, here's a query that illustrates what I'm on about. I found this > query[1] in a blog post[2]. > > ``` > WITH RECURSIVE typeinfo_tree( > oid, ns, name, kind, basetype, elemtype, elemdelim, > range_subtype, attrtypoids, attrnames, depth) > AS ( > SELECT > ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, > ti.elemtype, ti.elemdelim, ti.range_subtype, > ti.attrtypoids, ti.attrnames, 0 > FROM > ( > SELECT > t.oid AS oid, > ns.nspname AS ns, > t.typname AS name, > t.typtype AS kind, > (CASE WHEN t.typtype = 'd' THEN > (WITH RECURSIVE typebases(oid, depth) AS ( > SELECT > t2.typbasetype AS oid, > 0 AS depth > FROM > pg_type t2 > WHERE > t2.oid = t.oid > UNION ALL > SELECT > t2.typbasetype AS oid, > tb.depth + 1 AS depth > FROM > pg_type t2, > typebases tb > WHERE > tb.oid = t2.oid > AND t2.typbasetype != 0 > ) SELECT oid FROM typebases ORDER BY depth DESC LIMIT 1) > ELSE NULL > END) AS basetype, > t.typelem AS elemtype, > elem_t.typdelim AS elemdelim, > range_t.rngsubtype AS range_subtype, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.atttypid ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrtypoids, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.attname::text ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrnames > FROM > pg_catalog.pg_type AS t > INNER JOIN pg_catalog.pg_namespace ns ON ( > ns.oid = t.typnamespace) > LEFT JOIN pg_type elem_t ON ( > t.typlen = -1 AND > t.typelem != 0 AND > t.typelem = elem_t.oid > ) > LEFT JOIN pg_range range_t ON ( > t.oid = range_t.rngtypid > ) > ) AS ti > WHERE > ti.oid = any(ARRAY[16,17]::oid[]) > > UNION ALL > > SELECT > ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, > ti.elemtype, ti.elemdelim, ti.range_subtype, > ti.attrtypoids, ti.attrnames, tt.depth + 1 > FROM > ( > SELECT > t.oid AS oid, > ns.nspname AS ns, > t.typname AS name, > t.typtype AS kind, > (CASE WHEN t.typtype = 'd' THEN > (WITH RECURSIVE typebases(oid, depth) AS ( > SELECT > t2.typbasetype AS oid, > 0 AS depth > FROM > pg_type t2 > WHERE > t2.oid = t.oid > UNION ALL > SELECT > t2.typbasetype AS oid, > tb.depth + 1 AS depth > FROM > pg_type t2, > typebases tb > WHERE > tb.oid = t2.oid > AND t2.typbasetype != 0 > ) SELECT oid FROM typebases ORDER BY depth DESC LIMIT 1) > ELSE NULL > END) AS basetype, > t.typelem AS elemtype, > elem_t.typdelim AS elemdelim, > range_t.rngsubtype AS range_subtype, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.atttypid ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrtypoids, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.attname::text ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrnames > FROM > pg_catalog.pg_type AS t > INNER JOIN pg_catalog.pg_namespace ns ON ( > ns.oid = t.typnamespace) > LEFT JOIN pg_type elem_t ON ( > t.typlen = -1 AND > t.typelem != 0 AND > t.typelem = elem_t.oid > ) > LEFT JOIN pg_range range_t ON ( > t.oid = range_t.rngtypid > ) > ) ti, > typeinfo_tree tt > WHERE > (tt.elemtype IS NOT NULL AND ti.oid = tt.elemtype) > OR (tt.attrtypoids IS NOT NULL AND ti.oid = any(tt.attrtypoids)) > OR (tt.range_subtype IS NOT NULL AND ti.oid = tt.range_subtype) > ) > SELECT DISTINCT > *, > basetype::regtype::text AS basetype_name, > elemtype::regtype::text AS elemtype_name, > range_subtype::regtype::text AS range_subtype_name > FROM > typeinfo_tree > ORDER BY > depth DESC; > ``` > > I did an EXPLAIN ANALYZE and at the bottom you see this: > > Planning Time: 2.606 ms > JIT: > Functions: 148 > Options: Inlining true, Optimization true, Expressions true, Deforming > true > Timing: Generation 19.670 ms, Inlining 19.224 ms, Optimization 435.153 > ms, Emission 282.216 ms, Total 756.263 ms > Execution Time: 757.643 ms > > Average time to optimize, per function 435.153/148 = 2.940ms; > average time to emit per function 282.216/148 = 1.906ms > > Now let's change the query by making the first innermost recursive CTE into > non-recursive; just delete the RECURSIVE keyword and everything after the > UNION > ALL. You now get this query. > > ``` > explain analyze > WITH RECURSIVE typeinfo_tree( > oid, ns, name, kind, basetype, elemtype, elemdelim, > range_subtype, attrtypoids, attrnames, depth) > AS ( > SELECT > ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, > ti.elemtype, ti.elemdelim, ti.range_subtype, > ti.attrtypoids, ti.attrnames, 0 > FROM > ( > SELECT > t.oid AS oid, > ns.nspname AS ns, > t.typname AS name, > t.typtype AS kind, > (CASE WHEN t.typtype = 'd' THEN > (WITH typebases(oid, depth) AS ( > SELECT > t2.typbasetype AS oid, > 0 AS depth > FROM > pg_type t2 > WHERE > t2.oid = t.oid > ) SELECT oid FROM typebases ORDER BY depth DESC LIMIT 1) > ELSE NULL > END) AS basetype, > t.typelem AS elemtype, > elem_t.typdelim AS elemdelim, > range_t.rngsubtype AS range_subtype, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.atttypid ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrtypoids, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.attname::text ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrnames > FROM > pg_catalog.pg_type AS t > INNER JOIN pg_catalog.pg_namespace ns ON ( > ns.oid = t.typnamespace) > LEFT JOIN pg_type elem_t ON ( > t.typlen = -1 AND > t.typelem != 0 AND > t.typelem = elem_t.oid > ) > LEFT JOIN pg_range range_t ON ( > t.oid = range_t.rngtypid > ) > ) AS ti > WHERE > ti.oid = any(ARRAY[16,17]::oid[]) > > UNION ALL > > SELECT > ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, > ti.elemtype, ti.elemdelim, ti.range_subtype, > ti.attrtypoids, ti.attrnames, tt.depth + 1 > FROM > ( > SELECT > t.oid AS oid, > ns.nspname AS ns, > t.typname AS name, > t.typtype AS kind, > (CASE WHEN t.typtype = 'd' THEN > (WITH RECURSIVE typebases(oid, depth) AS ( > SELECT > t2.typbasetype AS oid, > 0 AS depth > FROM > pg_type t2 > WHERE > t2.oid = t.oid > UNION ALL > SELECT > t2.typbasetype AS oid, > tb.depth + 1 AS depth > FROM > pg_type t2, > typebases tb > WHERE > tb.oid = t2.oid > AND t2.typbasetype != 0 > ) SELECT oid FROM typebases ORDER BY depth DESC LIMIT 1) > ELSE NULL > END) AS basetype, > t.typelem AS elemtype, > elem_t.typdelim AS elemdelim, > range_t.rngsubtype AS range_subtype, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.atttypid ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrtypoids, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.attname::text ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrnames > FROM > pg_catalog.pg_type AS t > INNER JOIN pg_catalog.pg_namespace ns ON ( > ns.oid = t.typnamespace) > LEFT JOIN pg_type elem_t ON ( > t.typlen = -1 AND > t.typelem != 0 AND > t.typelem = elem_t.oid > ) > LEFT JOIN pg_range range_t ON ( > t.oid = range_t.rngtypid > ) > ) ti, > typeinfo_tree tt > WHERE > (tt.elemtype IS NOT NULL AND ti.oid = tt.elemtype) > OR (tt.attrtypoids IS NOT NULL AND ti.oid = any(tt.attrtypoids)) > OR (tt.range_subtype IS NOT NULL AND ti.oid = tt.range_subtype) > ) > > SELECT DISTINCT > *, > basetype::regtype::text AS basetype_name, > elemtype::regtype::text AS elemtype_name, > range_subtype::regtype::text AS range_subtype_name > FROM > typeinfo_tree > ORDER BY > depth DESC > ``` > > At the bottom of the explain you get this. > > Planning Time: 2.508 ms > JIT: > Functions: 137 > Options: Inlining true, Optimization true, Expressions true, Deforming > true > Timing: Generation 10.346 ms, Inlining 10.210 ms, Optimization 374.103 > ms, Emission 254.557 ms, Total 649.216 ms > Execution Time: 650.168 ms > > Average time to optimize, per function: 374.103/137 = 2.730ms > Average time to emit, per function 254.557 / 137 = 1.858ms > > > Now do it one more time, with the second innermost recursive CTE. You get > this > query. > > ``` > explain analyze > WITH RECURSIVE typeinfo_tree( > oid, ns, name, kind, basetype, elemtype, elemdelim, > range_subtype, attrtypoids, attrnames, depth) > AS ( > SELECT > ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, > ti.elemtype, ti.elemdelim, ti.range_subtype, > ti.attrtypoids, ti.attrnames, 0 > FROM > ( > SELECT > t.oid AS oid, > ns.nspname AS ns, > t.typname AS name, > t.typtype AS kind, > (CASE WHEN t.typtype = 'd' THEN > (WITH typebases(oid, depth) AS ( > SELECT > t2.typbasetype AS oid, > 0 AS depth > FROM > pg_type t2 > WHERE > t2.oid = t.oid > ) SELECT oid FROM typebases ORDER BY depth DESC LIMIT 1) > ELSE NULL > END) AS basetype, > t.typelem AS elemtype, > elem_t.typdelim AS elemdelim, > range_t.rngsubtype AS range_subtype, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.atttypid ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrtypoids, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.attname::text ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrnames > FROM > pg_catalog.pg_type AS t > INNER JOIN pg_catalog.pg_namespace ns ON ( > ns.oid = t.typnamespace) > LEFT JOIN pg_type elem_t ON ( > t.typlen = -1 AND > t.typelem != 0 AND > t.typelem = elem_t.oid > ) > LEFT JOIN pg_range range_t ON ( > t.oid = range_t.rngtypid > ) > ) AS ti > WHERE > ti.oid = any(ARRAY[16,17]::oid[]) > > UNION ALL > > SELECT > ti.oid, ti.ns, ti.name, ti.kind, ti.basetype, > ti.elemtype, ti.elemdelim, ti.range_subtype, > ti.attrtypoids, ti.attrnames, tt.depth + 1 > FROM > ( > SELECT > t.oid AS oid, > ns.nspname AS ns, > t.typname AS name, > t.typtype AS kind, > (CASE WHEN t.typtype = 'd' THEN > (WITH typebases(oid, depth) AS ( > SELECT > t2.typbasetype AS oid, > 0 AS depth > FROM > pg_type t2 > WHERE > t2.oid = t.oid > ) SELECT oid FROM typebases ORDER BY depth DESC LIMIT 1) > ELSE NULL > END) AS basetype, > t.typelem AS elemtype, > elem_t.typdelim AS elemdelim, > range_t.rngsubtype AS range_subtype, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.atttypid ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrtypoids, > (CASE WHEN t.typtype = 'c' THEN > (SELECT > array_agg(ia.attname::text ORDER BY ia.attnum) > FROM > pg_attribute ia > INNER JOIN pg_class c > ON (ia.attrelid = c.oid) > WHERE > ia.attnum > 0 AND NOT ia.attisdropped > AND c.reltype = t.oid) > ELSE NULL > END) AS attrnames > FROM > pg_catalog.pg_type AS t > INNER JOIN pg_catalog.pg_namespace ns ON ( > ns.oid = t.typnamespace) > LEFT JOIN pg_type elem_t ON ( > t.typlen = -1 AND > t.typelem != 0 AND > t.typelem = elem_t.oid > ) > LEFT JOIN pg_range range_t ON ( > t.oid = range_t.rngtypid > ) > ) ti, > typeinfo_tree tt > WHERE > (tt.elemtype IS NOT NULL AND ti.oid = tt.elemtype) > OR (tt.attrtypoids IS NOT NULL AND ti.oid = any(tt.attrtypoids)) > OR (tt.range_subtype IS NOT NULL AND ti.oid = tt.range_subtype) > ) > > SELECT DISTINCT > *, > basetype::regtype::text AS basetype_name, > elemtype::regtype::text AS elemtype_name, > range_subtype::regtype::text AS range_subtype_name > FROM > typeinfo_tree > ORDER BY > depth DESC; > ``` > > And the JIT numbers at the bottom look like this: > > Planning Time: 2.041 ms > JIT: > Functions: 126 > Options: Inlining false, Optimization true, Expressions true, Deforming > true > Timing: Generation 10.002 ms, Inlining 0.000 ms, Optimization 229.128 > ms, Emission 167.338 ms, Total 406.469 ms > Execution Time: 407.315 ms > > Average time to optimize per function 229.128 / 126 = 1.181ms > Average time to emit per function 167.338 / 126 = 1.328ms > > > In summary, > > Query 1, 148 functions JIT-compiled. > Average time to optimize, per function 435.153/148 = 2.940ms; > average time to emit per function 282.216/148 = 1.906ms > > Query 2, 137 functions JIT-compiled. > Average time to optimize, per function: 374.103/137 = 2.730ms > Average time to emit, per function 254.557 / 137 = 1.858ms > > Query 3, 126 functions JIT-compiled. > Average time to optimize per function 229.128 / 126 = 1.181ms > Average time to emit per function 167.338 / 126 = 1.328ms > > ???? Something looks very wrong here. > > [1] https://gist.github.com/saicitus/251ba20b211e9e73285af35e61b19580 > [2] > https://dev.to/xenatisch/cascade-of-doom-jit-and-how-a-postgres-update-led-to-70-failure-on-a-critical-national-service-3f2a > > -- > Álvaro Herrera PostgreSQL Developer — > https://www.EnterpriseDB.com/ > "Java is clearly an example of money oriented programming" (A. Stepanov) > > > Hi, For the 3rd query, I noticed some difference in options: Options: Inlining false, Optimization true, Expressions true, Deforming true Inlining was true for the first two queries. FYI